import { useEffect, useMemo, useRef, useState } from 'react';
import type { DemoLocale, DemoMode, ProgressStep, ProgressStepStatus, TraceItem } from './types';
import MarketplaceFeatureDemo from './MarketplaceFeatureDemo';
import { callVoiceTool } from './liveApi';
import type { LiveVoiceToolUi } from './liveApi';

type MarketplaceMode = 'hybrid' | 'products' | 'stores' | 'stats';

type ProductRecord = {
  id: string;
  name: string;
  category: string;
  price: number;
  unit: string;
  stock: number;
  tags: string[];
  location: string;
  seller: string;
  trend: number;
};

type StoreRecord = {
  id: string;
  name: string;
  type: 'retail' | 'restaurant' | 'wholesale' | 'co-op';
  location: string;
  buyingFocus: string[];
  responseRate: number;
  activeListings: number;
  rating: number;
};

type RankedProduct = ProductRecord & { score: number };
type RankedStore = StoreRecord & { score: number };

type MarketplaceStats = {
  sellers: number;
  buyers: number;
  products: number;
  stores: number;
  avgResponseRate: number;
  weeklyDemandIndex: number;
};

type MarketplaceStepTemplate = {
  id: string;
  label: string;
  runningDetail: string;
  doneDetail: string;
  kind: TraceItem['kind'];
  delayMs: number;
};

type MarketplaceDemoPanelProps = {
  mode: DemoMode;
  locale: DemoLocale;
  onWorkingChange: (working: boolean) => void;
  onWorkflowInit: (steps: ProgressStep[]) => void;
  onStepStatus: (stepId: string, status: ProgressStepStatus, detail?: string) => void;
  onTrace: (item: TraceItem) => void;
  onClearPanels: () => void;
  queuedPrompt: string | null;
  onConsumeQueuedPrompt: () => void;
};

const PRODUCT_DATA: ProductRecord[] = [
  {
    id: 'prd-101',
    name: 'Free-range Eggs',
    category: 'Eggs',
    price: 118,
    unit: 'box',
    stock: 48,
    tags: ['egg', 'protein', 'fresh'],
    location: 'Hsinchu',
    seller: 'Beipu Greenfield Farm',
    trend: 84,
  },
  {
    id: 'prd-102',
    name: 'Organic Spinach Bundle',
    category: 'Vegetables',
    price: 72,
    unit: 'bundle',
    stock: 63,
    tags: ['leafy', 'organic', 'salad'],
    location: 'Taoyuan',
    seller: 'Morning Leaf Cooperative',
    trend: 69,
  },
  {
    id: 'prd-103',
    name: 'Golden Sweet Corn',
    category: 'Produce',
    price: 95,
    unit: 'pack',
    stock: 64,
    tags: ['corn', 'sweet', 'seasonal'],
    location: 'Miaoli',
    seller: 'Golden Ridge Farm',
    trend: 77,
  },
  {
    id: 'prd-104',
    name: 'Ariake Seaweed Tofu',
    category: 'Tofu',
    price: 145,
    unit: 'set',
    stock: 18,
    tags: ['tofu', 'protein', 'vegan'],
    location: 'Taichung',
    seller: 'Blue Harbor Foods',
    trend: 58,
  },
  {
    id: 'prd-105',
    name: 'Premium Cherry Tomatoes',
    category: 'Produce',
    price: 160,
    unit: 'box',
    stock: 32,
    tags: ['tomato', 'snack', 'fruit'],
    location: 'Tainan',
    seller: 'Red Orchard Collective',
    trend: 73,
  },
  {
    id: 'prd-106',
    name: 'Jasmine Rice 2kg',
    category: 'Grains',
    price: 210,
    unit: 'bag',
    stock: 25,
    tags: ['rice', 'staple', 'bulk'],
    location: 'Yunlin',
    seller: 'Riverbank Fields',
    trend: 66,
  },
  {
    id: 'prd-107',
    name: 'Fresh Strawberries',
    category: 'Fruit',
    price: 245,
    unit: 'box',
    stock: 16,
    tags: ['fruit', 'dessert', 'seasonal'],
    location: 'Nantou',
    seller: 'Suncrest Berry Farm',
    trend: 88,
  },
  {
    id: 'prd-108',
    name: 'Young Ginger Pack',
    category: 'Produce',
    price: 86,
    unit: 'pack',
    stock: 40,
    tags: ['ginger', 'spice', 'seasoning'],
    location: 'Pingtung',
    seller: 'South Harvest Garden',
    trend: 55,
  },
];

const STORE_DATA: StoreRecord[] = [
  {
    id: 'str-201',
    name: 'Fresh Table Market',
    type: 'retail',
    location: 'Taipei',
    buyingFocus: ['Eggs', 'Fruit', 'Vegetables'],
    responseRate: 0.92,
    activeListings: 18,
    rating: 4.7,
  },
  {
    id: 'str-202',
    name: 'Harvest Bento Kitchen',
    type: 'restaurant',
    location: 'Hsinchu',
    buyingFocus: ['Eggs', 'Tofu', 'Produce'],
    responseRate: 0.87,
    activeListings: 11,
    rating: 4.5,
  },
  {
    id: 'str-203',
    name: 'Island Bulk Foods',
    type: 'wholesale',
    location: 'Taichung',
    buyingFocus: ['Grains', 'Eggs', 'Produce'],
    responseRate: 0.84,
    activeListings: 22,
    rating: 4.4,
  },
  {
    id: 'str-204',
    name: 'Green Basket Co-op',
    type: 'co-op',
    location: 'Tainan',
    buyingFocus: ['Vegetables', 'Fruit', 'Grains'],
    responseRate: 0.89,
    activeListings: 14,
    rating: 4.6,
  },
  {
    id: 'str-205',
    name: 'Seaside Family Mart',
    type: 'retail',
    location: 'Keelung',
    buyingFocus: ['Fruit', 'Produce'],
    responseRate: 0.81,
    activeListings: 9,
    rating: 4.1,
  },
  {
    id: 'str-206',
    name: 'Lotus Garden Restaurant',
    type: 'restaurant',
    location: 'Taoyuan',
    buyingFocus: ['Tofu', 'Vegetables', 'Rice'],
    responseRate: 0.9,
    activeListings: 13,
    rating: 4.8,
  },
];

const now = () =>
  new Date().toLocaleTimeString([], {
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit',
  });

const sleep = (ms: number) =>
  new Promise<void>((resolve) => {
    setTimeout(resolve, ms);
  });

function makeId(prefix: string): string {
  return `${prefix}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`;
}

function normalize(text: string): string {
  return text.trim().toLowerCase();
}

function tokenize(query: string): string[] {
  return normalize(query)
    .split(/[\s,]+/)
    .map((token) => token.trim())
    .filter(Boolean);
}

function buildTrace(
  kind: TraceItem['kind'],
  title: string,
  detail: string,
  status: TraceItem['status'],
  payload?: Record<string, unknown>
): TraceItem {
  return {
    id: makeId('trace'),
    kind,
    title,
    detail,
    status,
    payload,
    timestamp: now(),
  };
}

function categoryLabel(locale: DemoLocale, value: string): string {
  if (locale !== 'zh-TW') return value;
  const labels: Record<string, string> = {
    all: '全部',
    Eggs: '蛋品',
    Vegetables: '蔬菜',
    Produce: '農產',
    Tofu: '豆製品',
    Grains: '穀物',
    Fruit: '水果',
  };
  return labels[value] ?? value;
}

function storeTypeLabel(locale: DemoLocale, value: string): string {
  if (locale !== 'zh-TW') return value;
  const labels: Record<string, string> = {
    all: '全部',
    retail: '零售',
    restaurant: '餐飲',
    wholesale: '批發',
    'co-op': '合作社',
  };
  return labels[value] ?? value;
}

function focusLabel(locale: DemoLocale, value: string): string {
  if (locale !== 'zh-TW') return value;
  const labels: Record<string, string> = {
    Eggs: '蛋品',
    Fruit: '水果',
    Vegetables: '蔬菜',
    Tofu: '豆製品',
    Produce: '農產',
    Grains: '穀物',
    Rice: '米',
  };
  return labels[value] ?? value;
}

function computeMarketplaceStats(products: ProductRecord[], stores: StoreRecord[]): MarketplaceStats {
  const responseRateAverage =
    stores.length > 0 ? stores.reduce((sum, store) => sum + store.responseRate, 0) / stores.length : 0;
  const weeklyDemandIndex =
    products.length > 0 ? Math.round(products.reduce((sum, product) => sum + product.trend, 0) / products.length) : 0;
  return {
    sellers: 42,
    buyers: 67,
    products: products.length,
    stores: stores.length,
    avgResponseRate: responseRateAverage,
    weeklyDemandIndex,
  };
}

function toRankedProductsFromUi(ui: LiveVoiceToolUi | undefined, limit: number): RankedProduct[] {
  const rows = Array.isArray(ui?.items) ? ui.items : [];
  return rows.slice(0, limit).map((item, index) => {
    const row = typeof item === 'object' && item ? (item as Record<string, unknown>) : {};
    return {
      id: typeof row.id === 'string' ? row.id : `live-product-${index}`,
      name: typeof row.name === 'string' ? row.name : `Product ${index + 1}`,
      category: typeof row.category === 'string' ? row.category : 'General',
      price: typeof row.price === 'number' ? row.price : 0,
      unit: typeof row.unit === 'string' ? row.unit : 'unit',
      stock: typeof row.stock === 'number' ? row.stock : 0,
      tags: [],
      location: typeof row.location === 'string' ? row.location : '-',
      seller: typeof row.seller === 'string' ? row.seller : '-',
      trend: Math.max(10, 100 - index * 8),
      score: Math.max(18, 100 - index * 12),
    };
  });
}

function toRankedStoresFromUi(ui: LiveVoiceToolUi | undefined, limit: number): RankedStore[] {
  const rows = Array.isArray(ui?.items) ? ui.items : [];
  return rows.slice(0, limit).map((item, index) => {
    const row = typeof item === 'object' && item ? (item as Record<string, unknown>) : {};
    const sourceType =
      typeof row.type === 'string' &&
      (row.type === 'retail' || row.type === 'restaurant' || row.type === 'wholesale' || row.type === 'co-op')
        ? row.type
        : 'retail';
    return {
      id: typeof row.id === 'string' ? row.id : `live-store-${index}`,
      name: typeof row.name === 'string' ? row.name : `Store ${index + 1}`,
      type: sourceType,
      location: typeof row.location === 'string' ? row.location : '-',
      buyingFocus: [],
      responseRate: 0.8,
      activeListings: typeof row.activeListings === 'number' ? row.activeListings : 0,
      rating: typeof row.rating === 'number' ? row.rating : 4,
      score: Math.max(20, 100 - index * 12),
    };
  });
}

function toMarketplaceStatsFromUi(ui: LiveVoiceToolUi | undefined): MarketplaceStats | null {
  const rows = Array.isArray(ui?.items) ? ui.items : [];
  if (!rows.length) return null;
  const map: Record<string, number> = {};
  for (const row of rows) {
    if (typeof row !== 'object' || !row) continue;
    const item = row as Record<string, unknown>;
    const label = typeof item.label === 'string' ? item.label.toLowerCase() : '';
    const value = typeof item.value === 'number' ? item.value : typeof item.value === 'string' ? Number(item.value) : NaN;
    if (!label || Number.isNaN(value)) continue;
    map[label] = value;
  }
  return {
    sellers: map.sellers ?? map['賣家'] ?? 0,
    buyers: map.buyers ?? map['買家'] ?? 0,
    products: map.products ?? map['產品'] ?? map['商品'] ?? 0,
    stores: map.stores ?? map['店家'] ?? 0,
    avgResponseRate: 0,
    weeklyDemandIndex: 0,
  };
}

function scoreProduct(
  record: ProductRecord,
  queryTokens: string[],
  category: string,
  minPrice: number,
  maxPrice: number
): number {
  if (category !== 'all' && record.category !== category) return -1;
  if (record.price < minPrice || record.price > maxPrice) return -1;

  let score = 20 + Math.round(record.trend / 2);
  if (record.stock > 0) score += 12;
  if (queryTokens.length === 0) return score;

  for (const token of queryTokens) {
    const inName = normalize(record.name).includes(token);
    const inCategory = normalize(record.category).includes(token);
    const inTags = record.tags.some((tag) => normalize(tag).includes(token));
    const inSeller = normalize(record.seller).includes(token);
    const inLocation = normalize(record.location).includes(token);

    if (inName) score += 28;
    if (inCategory) score += 16;
    if (inTags) score += 12;
    if (inSeller) score += 9;
    if (inLocation) score += 8;
  }

  return score;
}

function scoreStore(record: StoreRecord, queryTokens: string[], type: string, location: string): number {
  if (type !== 'all' && record.type !== type) return -1;
  if (location.trim() && !normalize(record.location).includes(normalize(location))) return -1;

  let score = 26 + Math.round(record.responseRate * 30) + Math.round(record.rating * 5);
  if (queryTokens.length === 0) return score;

  for (const token of queryTokens) {
    const inName = normalize(record.name).includes(token);
    const inType = normalize(record.type).includes(token);
    const inFocus = record.buyingFocus.some((item) => normalize(item).includes(token));
    const inLocation = normalize(record.location).includes(token);

    if (inName) score += 26;
    if (inType) score += 14;
    if (inFocus) score += 12;
    if (inLocation) score += 10;
  }

  return score;
}

function buildSteps(locale: DemoLocale, mode: MarketplaceMode): MarketplaceStepTemplate[] {
  const isZh = locale === 'zh-TW';
  const steps: MarketplaceStepTemplate[] = [
    {
      id: 'market-step-1',
      label: isZh ? '解析搜尋意圖' : 'Parse marketplace intent',
      runningDetail: isZh ? '整理查詢、價格與位置條件。' : 'Normalizing query, price and location filters.',
      doneDetail: isZh ? '搜尋意圖已解析。' : 'Search intent resolved.',
      kind: 'planner',
      delayMs: 420,
    },
  ];

  if (mode === 'hybrid' || mode === 'products') {
    steps.push({
      id: 'market-step-2',
      label: isZh ? '呼叫商品搜尋' : 'Call product search',
      runningDetail: isZh ? '執行 product_search_public。' : 'Executing product_search_public route.',
      doneDetail: isZh ? '商品資料已回傳。' : 'Product results received.',
      kind: 'tool',
      delayMs: 520,
    });
  }

  if (mode === 'hybrid' || mode === 'stores') {
    steps.push({
      id: 'market-step-3',
      label: isZh ? '呼叫店家搜尋' : 'Call store search',
      runningDetail: isZh ? '執行 store_search_public。' : 'Executing store_search_public route.',
      doneDetail: isZh ? '店家資料已回傳。' : 'Store results received.',
      kind: 'tool',
      delayMs: 500,
    });
  }

  if (mode === 'hybrid' || mode === 'stats') {
    steps.push({
      id: 'market-step-4',
      label: isZh ? '取得市集統計' : 'Fetch marketplace stats',
      runningDetail: isZh ? '執行 marketplace_get_stats。' : 'Executing marketplace_get_stats route.',
      doneDetail: isZh ? '市集統計已更新。' : 'Marketplace stats updated.',
      kind: 'tool',
      delayMs: 420,
    });
  }

  steps.push({
    id: 'market-step-5',
    label: isZh ? '排名與渲染結果' : 'Rank and render results',
    runningDetail: isZh ? '進行相關性排序與展示組裝。' : 'Running relevance ranking and building output cards.',
    doneDetail: isZh ? '市集結果已就緒。' : 'Marketplace output is ready.',
    kind: 'renderer',
    delayMs: 360,
  });

  return steps;
}

const COPY = {
  en: {
    title: 'Marketplace Discovery',
    subtitle: 'Simulated public marketplace search and ranking workflow',
    statusRunning: 'Searching…',
    statusReady: 'Ready',
    modeLabel: 'Search Mode',
    modeHybrid: 'Hybrid (products + stores + stats)',
    modeProducts: 'Products only',
    modeStores: 'Stores only',
    modeStats: 'Stats only',
    queryLabel: 'Marketplace Query',
    queryPlaceholder: 'Search by keyword, category, location, or buyer intent.',
    filtersLabel: 'Filters',
    categoryLabel: 'Category',
    storeTypeLabel: 'Store Type',
    locationLabel: 'Location',
    minPriceLabel: 'Min Price',
    maxPriceLabel: 'Max Price',
    limitLabel: 'Result Limit',
    run: 'Run Search',
    stop: 'Stop',
    reset: 'Reset Output',
    recentLabel: 'Recent Queries',
    outputTitle: 'Marketplace Results',
    outputSubtitle: 'Ranked product/store cards with summary stats',
    emptyOutput: 'Run a search to preview marketplace discovery output.',
    noMatches: 'No records matched current filters. Try a broader query.',
    stopped: 'Marketplace search was stopped by user.',
    summary: 'Summary',
    statsTitle: 'Marketplace Stats',
    productsTitle: 'Ranked Products',
    storesTitle: 'Ranked Stores',
    metaTitle: 'Run Metadata',
    rawPayload: 'Structured payload',
    product: {
      price: 'Price',
      stock: 'Stock',
      location: 'Location',
      seller: 'Seller',
      trend: 'Trend',
      open: 'Open product',
      shortlist: 'Shortlist',
    },
    store: {
      type: 'Type',
      location: 'Location',
      focus: 'Buying focus',
      response: 'Response',
      listings: 'Listings',
      score: 'Score',
      open: 'Open store',
      contact: 'Draft outreach',
    },
    stat: {
      sellers: 'Sellers',
      buyers: 'Buyers',
      products: 'Products',
      stores: 'Stores',
      demand: 'Demand Index',
      response: 'Avg Response',
    },
    labels: {
      query: 'Query',
      mode: 'Mode',
      startedAt: 'Started At',
      duration: 'Duration',
      toolCalls: 'Tool Calls',
    },
  },
  'zh-TW': {
    title: '市集探索中心',
    subtitle: '前端模擬公開市集搜尋與排序流程',
    statusRunning: '搜尋中…',
    statusReady: '就緒',
    modeLabel: '搜尋模式',
    modeHybrid: '混合（商品 + 店家 + 統計）',
    modeProducts: '僅商品',
    modeStores: '僅店家',
    modeStats: '僅統計',
    queryLabel: '市集查詢',
    queryPlaceholder: '輸入關鍵字、品類、地區或買家需求。',
    filtersLabel: '篩選條件',
    categoryLabel: '商品分類',
    storeTypeLabel: '店家類型',
    locationLabel: '地區',
    minPriceLabel: '最低價格',
    maxPriceLabel: '最高價格',
    limitLabel: '顯示筆數',
    run: '開始搜尋',
    stop: '停止',
    reset: '重置輸出',
    recentLabel: '最近查詢',
    outputTitle: '市集結果',
    outputSubtitle: '含排序商品/店家卡片與統計摘要',
    emptyOutput: '請先執行搜尋以查看市集探索輸出。',
    noMatches: '目前條件找不到資料，可放寬條件再試。',
    stopped: '市集搜尋已由使用者停止。',
    summary: '摘要',
    statsTitle: '市集統計',
    productsTitle: '商品排名',
    storesTitle: '店家排名',
    metaTitle: '執行資訊',
    rawPayload: '結構化輸出',
    product: {
      price: '價格',
      stock: '庫存',
      location: '地區',
      seller: '賣家',
      trend: '趨勢',
      open: '開啟商品',
      shortlist: '加入候選',
    },
    store: {
      type: '類型',
      location: '地區',
      focus: '採購重點',
      response: '回覆率',
      listings: '需求數',
      score: '分數',
      open: '開啟店家',
      contact: '草擬聯絡',
    },
    stat: {
      sellers: '賣家',
      buyers: '買家',
      products: '商品',
      stores: '店家',
      demand: '需求指數',
      response: '平均回覆',
    },
    labels: {
      query: '查詢',
      mode: '模式',
      startedAt: '開始時間',
      duration: '耗時',
      toolCalls: '工具呼叫',
    },
  },
} as const;

export default function MarketplaceDemoPanel({
  mode: demoMode,
  locale,
  onWorkingChange,
  onWorkflowInit,
  onStepStatus,
  onTrace,
  onClearPanels,
  queuedPrompt,
  onConsumeQueuedPrompt,
}: MarketplaceDemoPanelProps) {
  const copy = COPY[locale];
  const modeLabels: Record<MarketplaceMode, string> = {
    hybrid: copy.modeHybrid,
    products: copy.modeProducts,
    stores: copy.modeStores,
    stats: copy.modeStats,
  };
  const [mode, setMode] = useState<MarketplaceMode>('hybrid');
  const [query, setQuery] = useState('');
  const [category, setCategory] = useState('all');
  const [storeType, setStoreType] = useState('all');
  const [location, setLocation] = useState('');
  const [minPrice, setMinPrice] = useState(0);
  const [maxPrice, setMaxPrice] = useState(260);
  const [limit, setLimit] = useState(6);
  const [isRunning, setIsRunning] = useState(false);
  const [products, setProducts] = useState<RankedProduct[]>([]);
  const [stores, setStores] = useState<RankedStore[]>([]);
  const [stats, setStats] = useState<MarketplaceStats | null>(null);
  const [summary, setSummary] = useState<string | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [recentQueries, setRecentQueries] = useState<string[]>([]);
  const [meta, setMeta] = useState<{
    query: string;
    mode: MarketplaceMode;
    startedAt: string;
    durationMs: number;
    toolCalls: string[];
  } | null>(null);

  const runTokenRef = useRef(0);
  const mountedRef = useRef(true);
  const currentStepRef = useRef<string | null>(null);

  const categoryOptions = useMemo(() => {
    const unique = Array.from(new Set(PRODUCT_DATA.map((record) => record.category)));
    return ['all', ...unique];
  }, []);

  const stepRunner = async (
    runToken: number,
    step: MarketplaceStepTemplate,
    payload?: Record<string, unknown>
  ): Promise<boolean> => {
    if (!mountedRef.current || runTokenRef.current !== runToken) return false;
    currentStepRef.current = step.id;
    onStepStatus(step.id, 'in_progress', step.runningDetail);
    onTrace(buildTrace(step.kind, step.label, step.runningDetail, 'running'));

    if (step.delayMs > 0) {
      await sleep(step.delayMs);
    }

    if (!mountedRef.current || runTokenRef.current !== runToken) return false;
    onStepStatus(step.id, 'completed', step.doneDetail);
    onTrace(buildTrace(step.kind, step.label, step.doneDetail, 'ok', payload));
    return true;
  };

  const stopSearch = () => {
    if (!isRunning) return;
    runTokenRef.current += 1;
    if (currentStepRef.current) {
      onStepStatus(currentStepRef.current, 'error', copy.stopped);
    }
    onTrace(buildTrace('tool', locale === 'zh-TW' ? '搜尋中止' : 'Search stopped', copy.stopped, 'error'));
    setError(copy.stopped);
    setIsRunning(false);
    onWorkingChange(false);
  };

  const resetOutput = () => {
    setProducts([]);
    setStores([]);
    setStats(null);
    setSummary(null);
    setError(null);
    setMeta(null);
    onClearPanels();
  };

  const runSearch = async (forcedQuery?: string) => {
    const activeQuery = (forcedQuery ?? query).trim();
    const steps = buildSteps(locale, mode);
    const runToken = runTokenRef.current + 1;
    runTokenRef.current = runToken;
    const startMs = Date.now();
    const tokens = tokenize(activeQuery);
    const toolCalls: string[] = [];

    onClearPanels();
    setIsRunning(true);
    onWorkingChange(true);
    setProducts([]);
    setStores([]);
    setStats(null);
    setSummary(null);
    setError(null);
    setMeta(null);

    if (activeQuery) {
      setRecentQueries((prev) => [activeQuery, ...prev.filter((item) => item !== activeQuery)].slice(0, 8));
    }

    onWorkflowInit(
      steps.map((step) => ({
        id: step.id,
        label: step.label,
        detail: step.runningDetail,
        status: 'pending',
      }))
    );

    try {
      const parsed = await stepRunner(runToken, steps[0], {
        query: activeQuery || '*',
        tokens,
        filters: { category, storeType, location, minPrice, maxPrice, limit },
      });
      if (!parsed) return;

      if (demoMode === 'live') {
        let liveProducts: RankedProduct[] = [];
        let liveStores: RankedStore[] = [];
        let liveStats: MarketplaceStats | null = null;

        const productStep = steps.find((step) => step.id === 'market-step-2');
        if (productStep) {
          toolCalls.push('product_search_public');
          const productReady = await stepRunner(runToken, productStep, {
            args: {
              nameContains: activeQuery || undefined,
              categoryEquals: category !== 'all' ? category : undefined,
              minPrice,
              maxPrice,
              limit,
            },
          });
          if (!productReady) return;
          const tool = await callVoiceTool({
            name: 'product_search_public',
            locale,
            args: {
              nameContains: activeQuery || undefined,
              categoryEquals: category !== 'all' ? category : undefined,
              minPrice,
              maxPrice,
              limit,
            },
          });
          liveProducts = toRankedProductsFromUi(tool.ui, limit);
          setProducts(liveProducts);
          onTrace(
            buildTrace(
              'tool',
              locale === 'zh-TW' ? '商品結果' : 'Product results',
              locale === 'zh-TW' ? `回傳 ${liveProducts.length} 筆商品` : `${liveProducts.length} products returned`,
              'ok',
              { count: liveProducts.length, uiKind: tool.ui?.kind || null }
            )
          );
        }

        const storeStep = steps.find((step) => step.id === 'market-step-3');
        if (storeStep) {
          toolCalls.push('store_search_public');
          const storeReady = await stepRunner(runToken, storeStep, {
            args: {
              nameContains: activeQuery || undefined,
              typeEquals: storeType !== 'all' ? storeType : undefined,
              locationContains: location || undefined,
              limit,
            },
          });
          if (!storeReady) return;
          const tool = await callVoiceTool({
            name: 'store_search_public',
            locale,
            args: {
              nameContains: activeQuery || undefined,
              typeEquals: storeType !== 'all' ? storeType : undefined,
              locationContains: location || undefined,
              limit,
            },
          });
          liveStores = toRankedStoresFromUi(tool.ui, limit);
          setStores(liveStores);
          onTrace(
            buildTrace(
              'tool',
              locale === 'zh-TW' ? '店家結果' : 'Store results',
              locale === 'zh-TW' ? `回傳 ${liveStores.length} 筆店家` : `${liveStores.length} stores returned`,
              'ok',
              { count: liveStores.length, uiKind: tool.ui?.kind || null }
            )
          );
        }

        const statsStep = steps.find((step) => step.id === 'market-step-4');
        if (statsStep) {
          toolCalls.push('marketplace_get_stats');
          const statsReady = await stepRunner(runToken, statsStep);
          if (!statsReady) return;
          const tool = await callVoiceTool({
            name: 'marketplace_get_stats',
            locale,
          });
          liveStats = toMarketplaceStatsFromUi(tool.ui) || computeMarketplaceStats(liveProducts, liveStores);
          setStats(liveStats);
          onTrace(
            buildTrace(
              'tool',
              locale === 'zh-TW' ? '市集統計' : 'Marketplace stats',
              locale === 'zh-TW' ? '已取得即時統計。' : 'Fetched live marketplace stats.',
              'ok',
              { uiKind: tool.ui?.kind || null }
            )
          );
        }

        const renderStep = steps.find((step) => step.id === 'market-step-5');
        if (renderStep) {
          const rendered = await stepRunner(runToken, renderStep, {
            products: liveProducts.length,
            stores: liveStores.length,
            stats: Boolean(liveStats),
            mode: 'live',
          });
          if (!rendered) return;
        }

        const summaryText =
          locale === 'zh-TW'
            ? `已完成即時市集搜尋：商品 ${liveProducts.length} 筆，店家 ${liveStores.length} 筆。`
            : `Live marketplace search completed: ${liveProducts.length} products and ${liveStores.length} stores.`;
        setSummary(summaryText);

        setMeta({
          query: activeQuery || '*',
          mode,
          startedAt: new Date(startMs).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' }),
          durationMs: Date.now() - startMs,
          toolCalls,
        });
        return;
      }

      const productStep = steps.find((step) => step.id === 'market-step-2');
      if (productStep) {
        toolCalls.push('product_search_public');
        const productReady = await stepRunner(runToken, productStep, {
          args: {
            nameContains: activeQuery || undefined,
            categoryEquals: category !== 'all' ? category : undefined,
            minPrice,
            maxPrice,
            limit,
          },
        });
        if (!productReady) return;

        const rankedProducts = PRODUCT_DATA.map((record) => ({
          ...record,
          score: scoreProduct(record, tokens, category, minPrice, maxPrice),
        }))
          .filter((record) => record.score > 0)
          .sort((a, b) => b.score - a.score)
          .slice(0, limit);
        setProducts(rankedProducts);

        onTrace(
          buildTrace(
            'tool',
            locale === 'zh-TW' ? '商品結果' : 'Product results',
            locale === 'zh-TW' ? `回傳 ${rankedProducts.length} 筆商品` : `${rankedProducts.length} products returned`,
            'ok',
            { count: rankedProducts.length }
          )
        );
      }

      const storeStep = steps.find((step) => step.id === 'market-step-3');
      if (storeStep) {
        toolCalls.push('store_search_public');
        const storeReady = await stepRunner(runToken, storeStep, {
          args: {
            nameContains: activeQuery || undefined,
            typeEquals: storeType !== 'all' ? storeType : undefined,
            locationContains: location || undefined,
            limit,
          },
        });
        if (!storeReady) return;

        const rankedStores = STORE_DATA.map((record) => ({
          ...record,
          score: scoreStore(record, tokens, storeType, location),
        }))
          .filter((record) => record.score > 0)
          .sort((a, b) => b.score - a.score)
          .slice(0, limit);
        setStores(rankedStores);

        onTrace(
          buildTrace(
            'tool',
            locale === 'zh-TW' ? '店家結果' : 'Store results',
            locale === 'zh-TW' ? `回傳 ${rankedStores.length} 筆店家` : `${rankedStores.length} stores returned`,
            'ok',
            { count: rankedStores.length }
          )
        );
      }

      const statsStep = steps.find((step) => step.id === 'market-step-4');
      if (statsStep) {
        toolCalls.push('marketplace_get_stats');
        const statsReady = await stepRunner(runToken, statsStep);
        if (!statsReady) return;
        setStats(computeMarketplaceStats(PRODUCT_DATA, STORE_DATA));
      }

      const renderStep = steps.find((step) => step.id === 'market-step-5');
      if (renderStep) {
        const rendered = await stepRunner(runToken, renderStep, {
          products: mode === 'stores' || mode === 'stats' ? undefined : 'ranked',
          stores: mode === 'products' || mode === 'stats' ? undefined : 'ranked',
          stats: mode === 'products' || mode === 'stores' ? undefined : 'included',
        });
        if (!rendered) return;
      }

      const productCount = mode === 'stores' || mode === 'stats' ? 0 : PRODUCT_DATA.filter((record) => scoreProduct(record, tokens, category, minPrice, maxPrice) > 0).slice(0, limit).length;
      const storeCount = mode === 'products' || mode === 'stats' ? 0 : STORE_DATA.filter((record) => scoreStore(record, tokens, storeType, location) > 0).slice(0, limit).length;
      const summaryText =
        locale === 'zh-TW'
          ? `已完成市集搜尋：商品 ${productCount} 筆，店家 ${storeCount} 筆。`
          : `Marketplace search completed: ${productCount} products and ${storeCount} stores ranked.`;
      setSummary(summaryText);

      setMeta({
        query: activeQuery || '*',
        mode,
        startedAt: new Date(startMs).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' }),
        durationMs: Date.now() - startMs,
        toolCalls,
      });
    } catch (runtimeError) {
      const message = runtimeError instanceof Error ? runtimeError.message : copy.stopped;
      setError(message);
      if (currentStepRef.current) {
        onStepStatus(currentStepRef.current, 'error', message);
      }
      onTrace(buildTrace('tool', locale === 'zh-TW' ? '搜尋錯誤' : 'Search error', message, 'error'));
    } finally {
      if (runTokenRef.current === runToken) {
        setIsRunning(false);
        onWorkingChange(false);
      }
    }
  };

  useEffect(() => {
    if (!queuedPrompt) return;

    const consume = async () => {
      setQuery(queuedPrompt);
      onConsumeQueuedPrompt();
      await runSearch(queuedPrompt);
    };

    void consume();
  }, [queuedPrompt]);

  useEffect(() => {
    mountedRef.current = true;
    return () => {
      mountedRef.current = false;
      runTokenRef.current += 1;
      onWorkingChange(false);
    };
  }, []);

  const hasResults = products.length > 0 || stores.length > 0 || Boolean(stats);

  return (
    <div className="marketplace-demo-root">
      <MarketplaceFeatureDemo locale={locale} isBusy={isRunning} />

      <header className="marketplace-demo-header">
        <div>
          <h3>{copy.title}</h3>
          <p>{copy.subtitle}</p>
        </div>
        <div className={`status-pill ${isRunning ? 'busy' : 'idle'}`}>{isRunning ? copy.statusRunning : copy.statusReady}</div>
      </header>

      <div className="marketplace-demo-layout">
        <section className="marketplace-input-panel">
          <label className="marketplace-field-block">
            <span>{copy.modeLabel}</span>
            <select value={mode} onChange={(event) => setMode(event.target.value as MarketplaceMode)} disabled={isRunning}>
              <option value="hybrid">{copy.modeHybrid}</option>
              <option value="products">{copy.modeProducts}</option>
              <option value="stores">{copy.modeStores}</option>
              <option value="stats">{copy.modeStats}</option>
            </select>
          </label>

          <label className="marketplace-field-block">
            <span>{copy.queryLabel}</span>
            <textarea
              rows={4}
              value={query}
              onChange={(event) => setQuery(event.target.value)}
              placeholder={copy.queryPlaceholder}
              disabled={isRunning}
            />
          </label>

          <div className="marketplace-filter-block">
            <h4>{copy.filtersLabel}</h4>

            {(mode === 'hybrid' || mode === 'products') ? (
              <div className="marketplace-filter-grid">
                <label>
                  <span>{copy.categoryLabel}</span>
                  <select value={category} onChange={(event) => setCategory(event.target.value)} disabled={isRunning}>
                    {categoryOptions.map((item) => (
                      <option key={item} value={item}>
                        {categoryLabel(locale, item)}
                      </option>
                    ))}
                  </select>
                </label>
                <label>
                  <span>{copy.minPriceLabel}</span>
                  <input
                    type="number"
                    value={minPrice}
                    onChange={(event) => setMinPrice(Number(event.target.value) || 0)}
                    disabled={isRunning}
                  />
                </label>
                <label>
                  <span>{copy.maxPriceLabel}</span>
                  <input
                    type="number"
                    value={maxPrice}
                    onChange={(event) => setMaxPrice(Number(event.target.value) || 0)}
                    disabled={isRunning}
                  />
                </label>
              </div>
            ) : null}

            {(mode === 'hybrid' || mode === 'stores') ? (
              <div className="marketplace-filter-grid">
                <label>
                  <span>{copy.storeTypeLabel}</span>
                  <select value={storeType} onChange={(event) => setStoreType(event.target.value)} disabled={isRunning}>
                    <option value="all">{storeTypeLabel(locale, 'all')}</option>
                    <option value="retail">{storeTypeLabel(locale, 'retail')}</option>
                    <option value="restaurant">{storeTypeLabel(locale, 'restaurant')}</option>
                    <option value="wholesale">{storeTypeLabel(locale, 'wholesale')}</option>
                    <option value="co-op">{storeTypeLabel(locale, 'co-op')}</option>
                  </select>
                </label>
                <label>
                  <span>{copy.locationLabel}</span>
                  <input
                    type="text"
                    value={location}
                    onChange={(event) => setLocation(event.target.value)}
                    placeholder={locale === 'zh-TW' ? '例如：台中' : 'e.g. Taichung'}
                    disabled={isRunning}
                  />
                </label>
              </div>
            ) : null}

            <label className="marketplace-field-block">
              <span>{copy.limitLabel}</span>
              <select value={limit} onChange={(event) => setLimit(Number(event.target.value))} disabled={isRunning}>
                <option value={4}>4</option>
                <option value={6}>6</option>
                <option value={8}>8</option>
                <option value={10}>10</option>
              </select>
            </label>
          </div>

          <div className="marketplace-action-row">
            <button type="button" className="primary-btn" onClick={() => void runSearch()} disabled={isRunning}>
              {copy.run}
            </button>
            {isRunning ? (
              <button type="button" className="ghost-btn" onClick={stopSearch}>
                {copy.stop}
              </button>
            ) : null}
            <button type="button" className="ghost-btn" onClick={resetOutput} disabled={isRunning}>
              {copy.reset}
            </button>
          </div>

          {recentQueries.length > 0 ? (
            <section className="marketplace-recent-block">
              <h4>{copy.recentLabel}</h4>
              <div className="marketplace-chip-row">
                {recentQueries.map((item) => (
                  <button key={item} type="button" className="prompt-chip" onClick={() => setQuery(item)} disabled={isRunning}>
                    {item}
                  </button>
                ))}
              </div>
            </section>
          ) : null}
        </section>

        <section className="marketplace-output-panel">
          <header>
            <h4>{copy.outputTitle}</h4>
            <p>{copy.outputSubtitle}</p>
          </header>

          {summary ? <div className="marketplace-note">{summary}</div> : null}
          {error ? <div className="marketplace-error">{error}</div> : null}

          {!hasResults && !isRunning ? <div className="marketplace-empty">{copy.emptyOutput}</div> : null}

          {stats ? (
            <article className="marketplace-stats-card">
              <h5>{copy.statsTitle}</h5>
              <div className="marketplace-stat-grid">
                <div>
                  <span>{copy.stat.sellers}</span>
                  <strong>{stats.sellers}</strong>
                </div>
                <div>
                  <span>{copy.stat.buyers}</span>
                  <strong>{stats.buyers}</strong>
                </div>
                <div>
                  <span>{copy.stat.products}</span>
                  <strong>{stats.products}</strong>
                </div>
                <div>
                  <span>{copy.stat.stores}</span>
                  <strong>{stats.stores}</strong>
                </div>
                <div>
                  <span>{copy.stat.demand}</span>
                  <strong>{stats.weeklyDemandIndex}</strong>
                </div>
                <div>
                  <span>{copy.stat.response}</span>
                  <strong>{Math.round(stats.avgResponseRate * 100)}%</strong>
                </div>
              </div>
            </article>
          ) : null}

          {(mode === 'hybrid' || mode === 'products') ? (
            <article className="marketplace-result-card">
              <h5>{copy.productsTitle}</h5>
              {products.length > 0 ? (
                <div className="marketplace-card-grid">
                  {products.map((item) => (
                    <section key={item.id} className="marketplace-entity-card">
                      <header>
                        <strong>{item.name}</strong>
                        <span>{categoryLabel(locale, item.category)}</span>
                      </header>
                      <div className="marketplace-metric-row">
                        <span>{copy.product.price}</span>
                        <strong>NT$ {item.price}/{item.unit}</strong>
                      </div>
                      <div className="marketplace-metric-row">
                        <span>{copy.product.stock}</span>
                        <strong>{item.stock}</strong>
                      </div>
                      <div className="marketplace-metric-row">
                        <span>{copy.product.location}</span>
                        <strong>{item.location}</strong>
                      </div>
                      <div className="marketplace-metric-row">
                        <span>{copy.product.seller}</span>
                        <strong>{item.seller}</strong>
                      </div>
                      <div className="marketplace-score-track">
                        <small>{copy.product.trend}</small>
                        <div>
                          <span style={{ width: `${Math.min(100, item.score)}%` }} />
                        </div>
                      </div>
                      <div className="action-row">
                        <button type="button" className="mini-btn">
                          {copy.product.open}
                        </button>
                        <button type="button" className="mini-btn">
                          {copy.product.shortlist}
                        </button>
                      </div>
                    </section>
                  ))}
                </div>
              ) : (
                <p className="marketplace-help-text">{copy.noMatches}</p>
              )}
            </article>
          ) : null}

          {(mode === 'hybrid' || mode === 'stores') ? (
            <article className="marketplace-result-card">
              <h5>{copy.storesTitle}</h5>
              {stores.length > 0 ? (
                <div className="marketplace-card-grid">
                  {stores.map((item) => (
                    <section key={item.id} className="marketplace-entity-card">
                      <header>
                        <strong>{item.name}</strong>
                        <span>{storeTypeLabel(locale, item.type)}</span>
                      </header>
                      <div className="marketplace-metric-row">
                        <span>{copy.store.location}</span>
                        <strong>{item.location}</strong>
                      </div>
                      <div className="marketplace-metric-row">
                        <span>{copy.store.response}</span>
                        <strong>{Math.round(item.responseRate * 100)}%</strong>
                      </div>
                      <div className="marketplace-metric-row">
                        <span>{copy.store.listings}</span>
                        <strong>{item.activeListings}</strong>
                      </div>
                      <div className="marketplace-metric-row">
                        <span>{copy.store.focus}</span>
                        <strong>{item.buyingFocus.slice(0, 2).map((focus) => focusLabel(locale, focus)).join(', ')}</strong>
                      </div>
                      <div className="marketplace-score-track">
                        <small>{copy.store.score}</small>
                        <div>
                          <span style={{ width: `${Math.min(100, item.score)}%` }} />
                        </div>
                      </div>
                      <div className="action-row">
                        <button type="button" className="mini-btn">
                          {copy.store.open}
                        </button>
                        <button type="button" className="mini-btn">
                          {copy.store.contact}
                        </button>
                      </div>
                    </section>
                  ))}
                </div>
              ) : (
                <p className="marketplace-help-text">{copy.noMatches}</p>
              )}
            </article>
          ) : null}

          {meta ? (
            <article className="marketplace-meta-card">
              <h5>{copy.metaTitle}</h5>
              <dl>
                <div>
                  <dt>{copy.labels.query}</dt>
                  <dd>{meta.query}</dd>
                </div>
                <div>
                  <dt>{copy.labels.mode}</dt>
                  <dd>{modeLabels[meta.mode]}</dd>
                </div>
                <div>
                  <dt>{copy.labels.startedAt}</dt>
                  <dd>{meta.startedAt}</dd>
                </div>
                <div>
                  <dt>{copy.labels.duration}</dt>
                  <dd>{meta.durationMs} ms</dd>
                </div>
                <div>
                  <dt>{copy.labels.toolCalls}</dt>
                  <dd>{meta.toolCalls.join(', ') || '-'}</dd>
                </div>
              </dl>

              <details>
                <summary>{copy.rawPayload}</summary>
                <pre>{JSON.stringify({ products, stores, stats, meta }, null, 2)}</pre>
              </details>
            </article>
          ) : null}
        </section>
      </div>
    </div>
  );
}
