const {
  useEffect: useEffectChatbot,
  useMemo: useMemoChatbot,
  useRef: useRefChatbot,
  useState: useStateChatbot,
} = React;

const CHATBOT_API_BASE = window.JAFUN_QUOTE_API_BASE || 'http://localhost:3001';
const CHATBOT_QUICK_PROMPTS = [
  '怎麼用 LINE 代購？',
  '運費和服務費怎麼算？',
  '出貨要幾天？',
  '可以代購樂天商品嗎？',
];
const CHATBOT_INITIAL_GREETING = 'こんにちは！我是 JaFun 的 AI 小幫手 ジャ子。\n有任何日本購物、代購、集運問題都可以問我。';

function chatbotSpeechRecognitionCtor() {
  return window.SpeechRecognition || window.webkitSpeechRecognition || null;
}

function chatbotMergeTranscript(baseText, transcript) {
  const base = String(baseText || '').trimEnd();
  const speechText = String(transcript || '').replace(/\s+/g, ' ').trim();
  if (!speechText) return base;
  return `${base}${base ? ' ' : ''}${speechText}`.slice(0, 900);
}

function chatbotSessionId() {
  const key = 'jafun-chatbot-session-id';
  try {
    const existing = window.sessionStorage.getItem(key);
    if (existing) return existing;
    const next = `chat_${Date.now().toString(36)}_${Math.random().toString(16).slice(2, 10)}`;
    window.sessionStorage.setItem(key, next);
    return next;
  } catch (error) {
    return `chat_${Date.now().toString(36)}`;
  }
}

function chatbotDecodeText(value) {
  const text = String(value || '');
  if (!/[&<]/.test(text)) return text;
  const textarea = document.createElement('textarea');
  textarea.innerHTML = text;
  return textarea.value;
}

function chatbotOptionSummary(product, selections = {}) {
  return (product?.options || []).map(option => {
    const value = option.values.find(item => item.id === selections[option.key]);
    return value ? `${option.label}: ${value.label}` : '';
  }).filter(Boolean).join(' / ');
}

function chatbotCartId(quote) {
  if (!quote?.product) return '';
  const selections = quote.selectedOptions || {};
  return `chatbot-quote-${quote.product.source}-${quote.product.productId}-${Object.values(selections).join('-')}`;
}

function chatbotCartItem(quote) {
  if (!quote?.product || !quote?.pricing) return null;
  const selections = quote.selectedOptions || {};
  return {
    id: quote.product.productId,
    cartId: chatbotCartId(quote),
    region: `AI 客服推薦 · ${quote.product.sourceLabel}`,
    name: chatbotDecodeText(quote.product.title),
    jname: chatbotDecodeText(quote.product.subtitle),
    price: quote.pricing.totalTWD,
    jpy: quote.pricing.itemSubtotalJPY,
    img: quote.product.image,
    optionSummary: chatbotOptionSummary(quote.product, selections),
    sourceLabel: quote.product.sourceLabel,
    sourceUrl: quote.product.sourceUrl,
    sourceType: quote.product.source,
    selectedOptions: selections,
    feeIncluded: true,
    shippingIncluded: true,
    quotePricing: quote.pricing,
  };
}

function chatbotSiteProductId(product) {
  return String(product?.id || product?.sku || product?.slug || '').trim();
}

function chatbotSiteProducts() {
  return (window.PRODUCTS || []).slice(0, 80).map(product => ({
    id: chatbotSiteProductId(product),
    slug: product.slug || '',
    sku: product.sku || '',
    name: product.name || '',
    jname: product.jname || '',
    region: product.region || '',
    price: Number(product.price) || 0,
    jpy: Number(product.jpy) || 0,
    img: product.img || '',
    badge: product.badge || '',
    tags: [
      product.region,
      product.badge,
      product.category,
      ...(product.categorySlugs || []),
      ...(product.tags || []),
    ].filter(Boolean).map(String),
  })).filter(product => product.id && product.name);
}

function chatbotFindSiteProduct(productLike) {
  const id = chatbotSiteProductId(productLike);
  const slug = String(productLike?.slug || '').trim();
  const sku = String(productLike?.sku || '').trim();
  const name = String(productLike?.name || '').trim();
  return (window.PRODUCTS || []).find(product => {
    return chatbotSiteProductId(product) === id
      || (slug && String(product.slug || '') === slug)
      || (sku && String(product.sku || '') === sku)
      || (name && String(product.name || '') === name);
  }) || productLike || null;
}

function chatbotSiteCartId(productLike) {
  const id = chatbotSiteProductId(productLike);
  return id ? `chatbot-site-${id}` : '';
}

function chatbotSiteCartItem(productLike) {
  const product = chatbotFindSiteProduct(productLike);
  if (!product) return null;
  return {
    ...product,
    id: product.id || chatbotSiteProductId(product),
    cartId: chatbotSiteCartId(product),
    region: product.region || 'JaFun 商城',
    name: product.name || '',
    jname: product.jname || 'JaFun selected product',
    price: Number(product.price) || 0,
    jpy: Number(product.jpy) || 0,
    img: product.img || 'assets/hero-optimized/hero-01.webp',
    optionSummary: product.optionSummary || '規格: 標準規格',
    selectedOptions: product.selectedOptions || { spec: '標準規格' },
  };
}

const CHATBOT_HISTORY_CONTENT_LIMIT = 900;

function chatbotCompactHistoryText(value, maxLength = CHATBOT_HISTORY_CONTENT_LIMIT) {
  const text = String(value || '').replace(/\s+/g, ' ').trim();
  if (text.length <= maxLength) return text;
  return `${text.slice(0, Math.max(0, maxLength - 1)).trim()}…`;
}

function chatbotHistoryContent(item) {
  const response = item.response || null;
  const facts = [];
  if (response?.intent) facts.push(`intent: ${response.intent}`);
  if (response?.quote?.product?.title) {
    facts.push(`quoteTitle: ${chatbotDecodeText(response.quote.product.title)}`);
    facts.push(`quoteSource: ${response.quote.product.sourceLabel || response.quote.product.source || ''}`);
    facts.push(`quoteTotalTWD: ${response.quote.pricing?.totalTWD || ''}`);
  }
  if (response?.recommendation?.searchQuery) facts.push(`searchQuery: ${response.recommendation.searchQuery}`);
  if (response?.recommendation?.intentSummary) facts.push(`intentSummary: ${response.recommendation.intentSummary}`);
  if (response?.recommendation?.recommendation?.title) facts.push(`fallbackRecommendation: ${chatbotDecodeText(response.recommendation.recommendation.title)}`);
  if (response?.siteProduct?.name) facts.push(`siteProduct: ${chatbotDecodeText(response.siteProduct.name)}`);
  if (response?.siteMatches?.length) facts.push(`siteMatches: ${response.siteMatches.map(product => chatbotDecodeText(product.name)).join(' / ')}`);
  return chatbotCompactHistoryText([
    chatbotCompactHistoryText(item.text, 520),
    facts.length ? `[JaFun context]\n${chatbotCompactHistoryText(facts.filter(Boolean).join('\n'), 340)}` : '',
  ].filter(Boolean).join('\n'));
}

function chatbotFriendlyErrorMessage(value) {
  const text = String(value || '').trim();
  if (!text) return 'AI 客服目前無法回應，請稍後再試或改用 LINE。';
  if (/history\.\d+\.content|must be shorter|maxLength|Validation failed/i.test(text)) {
    return '對話內容太長，我已重新整理上下文，請再送出一次。';
  }
  return text;
}

function chatbotLooksLikeWeakCandidateTitle(title) {
  const clean = String(title || '').trim().toLowerCase();
  if (!clean) return true;
  if (/^[a-z]{2,}\d{5,}$/i.test(clean)) return true;
  if (/^[a-z0-9_-]{8,}$/i.test(clean) && !/[\u3040-\u30ff\u3400-\u9fff]/u.test(clean)) return true;
  return false;
}

function ChatbotQuoteCard({ response, added, onAction }) {
  const quote = response?.quote;
  const recommendation = response?.recommendation;
  if (!quote && !recommendation?.recommendation) return null;

  if (quote) {
    const product = quote.product;
    const pricing = quote.pricing;
    return (
      <div className="chatbot-product-card">
        <img src={product.image} alt="" />
        <div className="chatbot-product-info">
          <span>{product.sourceLabel} · {product.brand}</span>
          <strong>{chatbotDecodeText(product.title)}</strong>
          <small>{chatbotOptionSummary(product, quote.selectedOptions) || product.subtitle}</small>
          <div className="chatbot-product-total">
            <span>預估總額</span>
            <strong>NT$ {pricing.totalTWD.toLocaleString()}</strong>
          </div>
          <div className="chatbot-product-actions">
            <button type="button" className="btn btn-primary" onClick={() => onAction({ type: 'add_to_cart', label: '加入購物車' }, response)}>
              {added ? '已加入' : '加入購物車'}
            </button>
            <button type="button" className="btn btn-ghost" onClick={() => onAction({ type: 'cart', label: '前往購物車', route: 'cart' }, response)}>
              前往購物車
            </button>
          </div>
        </div>
      </div>
    );
  }

  const candidate = recommendation.recommendation;
  const candidateTitle = chatbotDecodeText(candidate?.title || '');
  if (response?.reply?.includes('不開放自動下單') || chatbotLooksLikeWeakCandidateTitle(candidateTitle)) {
    return null;
  }
  return (
    <div className="chatbot-candidate-card">
      <span>{candidate.sourceLabel}</span>
      <strong>{candidateTitle}</strong>
      <small>{chatbotDecodeText(candidate.reason || recommendation.recommendedReason)}</small>
    </div>
  );
}

function ChatbotSiteProductCard({ response, addedCartIds, onAction }) {
  const products = response?.siteProduct
    ? [response.siteProduct]
    : (response?.siteMatches || []).slice(0, 3);
  if (!products.length) return null;

  return (
    <div className="chatbot-site-products">
      {products.map(product => {
        const cartId = chatbotSiteCartId(product);
        const added = !!addedCartIds[cartId];
        return (
          <div key={chatbotSiteProductId(product)} className="chatbot-product-card chatbot-site-card">
            <img src={product.img || 'assets/hero-optimized/hero-01.webp'} alt="" />
            <div className="chatbot-product-info">
              <span>JAFUN 商城 · {product.region || '日本選品'}</span>
              <strong>{chatbotDecodeText(product.name)}</strong>
              <small>{chatbotDecodeText(product.jname || product.reason || '站內已有相近商品')}</small>
              <div className="chatbot-product-total">
                <span>商品價格</span>
                <strong>{Number(product.price) ? `NT$ ${Number(product.price).toLocaleString()}` : '商品頁確認'}</strong>
              </div>
              <div className="chatbot-product-actions">
                <button
                  type="button"
                  className="btn btn-primary"
                  onClick={() => onAction({ type: 'site_product', label: '查看商品', route: 'product', productId: chatbotSiteProductId(product) }, response)}
                >
                  查看商品
                </button>
                <button
                  type="button"
                  className="btn btn-ghost"
                  onClick={() => onAction({ type: 'add_site_product_to_cart', label: '加入購物車', productId: chatbotSiteProductId(product) }, response)}
                >
                  {added ? '已加入' : '加入購物車'}
                </button>
              </div>
            </div>
          </div>
        );
      })}
    </div>
  );
}

function ChatbotMessage({ item, addedCartIds, onAction }) {
  const response = item.response || null;
  const cartId = response?.quote ? chatbotCartId(response.quote) : '';
  const quickActions = (response?.quickActions || []).filter(action => {
    if ((response?.siteProduct || response?.siteMatches?.length) && ['site_product', 'add_site_product_to_cart'].includes(action.type)) return false;
    return true;
  });
  return (
    <div className={`chatbot-message ${item.role === 'user' ? 'is-user' : 'is-assistant'}`}>
      <div className="chatbot-bubble">
        {item.text}
        {response?.guardrail?.inScope === false && (
          <div className="chatbot-scope-note">已限制在 JaFun 服務範圍內</div>
        )}
      </div>
      {item.role === 'assistant' && response && (
        <>
          <ChatbotSiteProductCard response={response} addedCartIds={addedCartIds} onAction={onAction} />
          <ChatbotQuoteCard response={response} added={!!addedCartIds[cartId]} onAction={onAction} />
          {!!quickActions.length && (
            <div className="chatbot-action-row">
              {quickActions.map((action, index) => (
                <button key={`${action.type}-${index}`} type="button" onClick={() => onAction(action, response)}>
                  {action.label}
                </button>
              ))}
            </div>
          )}
        </>
      )}
    </div>
  );
}

function ChatbotWidget({ onNav, onAddToCart }) {
  const [open, setOpen] = useStateChatbot(false);
  const [input, setInput] = useStateChatbot('');
  const [loading, setLoading] = useStateChatbot(false);
  const [unread, setUnread] = useStateChatbot(1);
  const [addedCartIds, setAddedCartIds] = useStateChatbot({});
  const [speechSupported, setSpeechSupported] = useStateChatbot(false);
  const [speechListening, setSpeechListening] = useStateChatbot(false);
  const [speechNotice, setSpeechNotice] = useStateChatbot('');
  const [messages, setMessages] = useStateChatbot([
    {
      id: 'welcome',
      role: 'assistant',
      text: CHATBOT_INITIAL_GREETING,
    },
  ]);
  const scrollRef = useRefChatbot(null);
  const inputRef = useRefChatbot(null);
  const openRef = useRefChatbot(open);
  const recognitionRef = useRefChatbot(null);
  const speechBaseRef = useRefChatbot('');
  const speechTranscriptRef = useRefChatbot('');

  const history = useMemoChatbot(() => messages
    .filter(item => item.role === 'user' || item.role === 'assistant')
    .slice(-6)
    .map(item => ({ role: item.role, content: chatbotHistoryContent(item) })), [messages]);

  useEffectChatbot(() => {
    openRef.current = open;
    if (open) setUnread(0);
    // 手機版客服視窗為全螢幕,開啟時鎖住背景捲動(避免滑到後面的首頁);桌面版的小視窗不受影響(由 styles.css 的 @media 限制)
    document.body.classList.toggle('chatbot-open', open);
    if (open) window.setTimeout(() => inputRef.current?.focus(), 120);
    return () => { document.body.classList.remove('chatbot-open'); };
  }, [open]);

  useEffectChatbot(() => {
    if (!open) return;
    scrollRef.current?.scrollTo({ top: scrollRef.current.scrollHeight, behavior: 'smooth' });
  }, [messages, loading, open]);

  useEffectChatbot(() => {
    const openFromMobileFooter = () => setOpen(true);
    window.addEventListener('jafun:chatbot-open', openFromMobileFooter);
    return () => window.removeEventListener('jafun:chatbot-open', openFromMobileFooter);
  }, []);

  useEffectChatbot(() => {
    setSpeechSupported(Boolean(chatbotSpeechRecognitionCtor()) && window.isSecureContext !== false);
    return () => {
      try {
        recognitionRef.current?.abort?.();
      } catch (error) {
        // Browser speech recognition cleanup is best-effort only.
      }
    };
  }, []);

  const appendAssistantError = (text) => {
    setMessages(current => [
      ...current,
      { id: `assistant-error-${Date.now()}`, role: 'assistant', text },
    ]);
  };

  const stopSpeechInput = () => {
    try {
      recognitionRef.current?.stop?.();
    } catch (error) {
      recognitionRef.current = null;
      setSpeechListening(false);
    }
  };

  const startSpeechInput = () => {
    const Recognition = chatbotSpeechRecognitionCtor();
    if (!Recognition || window.isSecureContext === false) {
      setSpeechNotice('這個瀏覽器暫不支援語音輸入，請改用文字輸入。');
      return;
    }

    try {
      recognitionRef.current?.abort?.();
      const recognition = new Recognition();
      recognition.lang = 'zh-TW';
      recognition.continuous = false;
      recognition.interimResults = true;
      recognition.maxAlternatives = 1;

      speechBaseRef.current = input;
      speechTranscriptRef.current = '';
      recognitionRef.current = recognition;

      recognition.onstart = () => {
        setSpeechListening(true);
        setSpeechNotice('正在聆聽，請說出想問或想買的內容。');
      };
      recognition.onresult = (event) => {
        let finalText = '';
        let interimText = '';
        for (let index = 0; index < event.results.length; index += 1) {
          const result = event.results[index];
          const transcript = result?.[0]?.transcript || '';
          if (result?.isFinal) finalText = `${finalText} ${transcript}`.trim();
          else interimText = `${interimText} ${transcript}`.trim();
        }
        speechTranscriptRef.current = finalText;
        setInput(chatbotMergeTranscript(speechBaseRef.current, `${finalText} ${interimText}`));
      };
      recognition.onerror = (event) => {
        const reason = event?.error === 'not-allowed'
          ? '請允許瀏覽器使用麥克風後再試一次。'
          : event?.error === 'no-speech'
            ? '沒有聽到內容，請再按一次麥克風重新輸入。'
            : '語音輸入暫時無法使用，請改用文字輸入。';
        setSpeechNotice(reason);
        setSpeechListening(false);
      };
      recognition.onend = () => {
        recognitionRef.current = null;
        setSpeechListening(false);
        if (speechTranscriptRef.current) {
          setSpeechNotice('已轉成文字，可確認後送出。');
        }
      };
      recognition.start();
    } catch (error) {
      recognitionRef.current = null;
      setSpeechListening(false);
      setSpeechNotice('語音輸入啟動失敗，請確認瀏覽器與麥克風權限。');
    }
  };

  const toggleSpeechInput = () => {
    if (loading) return;
    if (speechListening) {
      stopSpeechInput();
      return;
    }
    startSpeechInput();
  };

  const sendMessage = async (value) => {
    const text = String(value || input).trim();
    if (!text || loading) return;
    if (speechListening) stopSpeechInput();
    setSpeechNotice('');
    setInput('');
    const userMessage = { id: `user-${Date.now()}`, role: 'user', text };
    setMessages(current => [...current, userMessage]);
    setLoading(true);
    try {
      const response = await fetch(`${CHATBOT_API_BASE}/chatbot/message`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          message: text,
          history,
          sessionId: chatbotSessionId(),
          siteContext: {
            route: window.location.pathname.replace(/^\/|\/$/g, '') || 'home',
            pageUrl: window.location.href,
            products: chatbotSiteProducts(),
          },
          ...(window.jafunAnalyticsPayload?.('ai_chatbot') || { locale: 'zh-Hant' }),
        }),
      });
      if (!response.ok) {
        let message = 'AI 客服目前無法回應，請稍後再試或改用 LINE。';
        try {
          const payload = await response.json();
          message = Array.isArray(payload.message) ? payload.message.join('、') : (payload.message || message);
        } catch (error) {
          message = await response.text() || message;
        }
        throw new Error(chatbotFriendlyErrorMessage(message));
      }
      const payload = await response.json();
      if (payload.sessionId) {
        try {
          window.sessionStorage.setItem('jafun-chatbot-session-id', payload.sessionId);
        } catch (error) {
          // Session persistence is best-effort only.
        }
      }
      setMessages(current => [
        ...current,
        {
          id: `assistant-${Date.now()}`,
          role: 'assistant',
          text: chatbotDecodeText(payload.reply || '我已收到，請補充商品網址或需求細節。'),
          response: payload,
        },
      ]);
      if (!openRef.current) setUnread(current => current + 1);
    } catch (error) {
      appendAssistantError(error.message || 'AI 客服目前無法回應，請稍後再試或改用 LINE。');
      if (!openRef.current) setUnread(current => current + 1);
    } finally {
      setLoading(false);
    }
  };

  const addQuoteToCart = (response) => {
    const item = chatbotCartItem(response?.quote);
    if (!item) return;
    onAddToCart?.(item, 1);
    setAddedCartIds(current => ({ ...current, [item.cartId]: true }));
    setMessages(current => [
      ...current,
      {
        id: `assistant-cart-${Date.now()}`,
        role: 'assistant',
        text: '已加入購物車。你可以直接前往購物車結帳，或繼續詢問其他商品。',
      },
    ]);
  };

  const addSiteProductToCart = (response, action = {}) => {
    const product = response?.siteProduct
      || (response?.siteMatches || []).find(item => chatbotSiteProductId(item) === String(action.productId || ''))
      || { id: action.productId };
    const item = chatbotSiteCartItem(product);
    if (!item) return;
    onAddToCart?.(item, 1);
    setAddedCartIds(current => ({ ...current, [item.cartId]: true }));
    setMessages(current => [
      ...current,
      {
        id: `assistant-site-cart-${Date.now()}`,
        role: 'assistant',
        text: `已把「${item.name}」加入購物車。你可以前往購物車結帳，或繼續讓我幫你找其他日本商品。`,
      },
    ]);
  };

  const openSiteProduct = (response, action = {}) => {
    const product = response?.siteProduct
      || (response?.siteMatches || []).find(item => chatbotSiteProductId(item) === String(action.productId || ''))
      || { id: action.productId };
    const resolved = chatbotFindSiteProduct(product);
    if (resolved?.name) {
      onNav?.('product', { product: resolved });
    } else {
      onNav?.('shop');
    }
    setOpen(false);
  };

  const handleAction = (action, response) => {
    if (action.type === 'add_to_cart') {
      addQuoteToCart(response);
      return;
    }
    if (action.type === 'add_site_product_to_cart') {
      addSiteProductToCart(response, action);
      return;
    }
    if (action.type === 'site_product' || (action.route === 'product' && action.productId)) {
      openSiteProduct(response, action);
      return;
    }
    if (action.route) {
      onNav?.(action.route);
      setOpen(false);
      return;
    }
    if (action.url) {
      window.open(action.url, '_blank', 'noopener,noreferrer');
      return;
    }
    if (action.type === 'line') {
      window.openLineOfficial?.();
    }
  };

  return (
    <div className={`chatbot-widget ${open ? 'is-open' : ''}`}>
      <button
        className="chatbot-launcher"
        type="button"
        aria-label={open ? '關閉 JaFun AI 客服' : '開啟 JaFun AI 客服'}
        onClick={() => setOpen(current => !current)}
      >
        {open ? (
          <span className="chatbot-launcher-close" aria-hidden="true">
            <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2">
              <path d="M18 6L6 18M6 6l12 12" />
            </svg>
          </span>
        ) : (
          <>
            <span className="chatbot-launcher-icon" aria-hidden="true">
              <svg width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8">
                <path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z" />
              </svg>
            </span>
            {unread > 0 && <span className="chatbot-launcher-badge">{unread}</span>}
          </>
        )}
      </button>
      {open && (
        <section className="chatbot-panel" aria-label="JaFun AI 客服">
          <div className="chatbot-header">
            <div className="chatbot-header-main">
              <div className="chatbot-header-mark">ジャ</div>
              <div>
                <strong>ジャ子 · JaFun 客服</strong>
                <small>線上中 · 通常 1 分鐘內回覆</small>
              </div>
            </div>
            <button type="button" onClick={() => setOpen(false)} aria-label="關閉">
              <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
                <path d="M18 6L6 18M6 6l12 12" />
              </svg>
            </button>
          </div>
          <div className="chatbot-messages" ref={scrollRef}>
            {messages.map(item => (
              <ChatbotMessage key={item.id} item={item} addedCartIds={addedCartIds} onAction={handleAction} />
            ))}
            {loading && (
              <div className="chatbot-message is-assistant">
                <div className="chatbot-bubble">
                  <span className="chatbot-typing"><i /> <i /> <i /></span>
                </div>
              </div>
            )}
            {messages.length <= 1 && !loading && (
              <div className="chatbot-prompts">
                {CHATBOT_QUICK_PROMPTS.map(prompt => (
                  <button key={prompt} type="button" onClick={() => sendMessage(prompt)} disabled={loading}>
                    {prompt}
                  </button>
                ))}
              </div>
            )}
          </div>
          <form
            className="chatbot-input-row"
            onSubmit={(event) => {
              event.preventDefault();
              sendMessage(input);
            }}
          >
            <div className="chatbot-input-shell">
              <textarea
                ref={inputRef}
                value={input}
                onChange={event => {
                  setInput(event.target.value);
                  if (!speechListening) setSpeechNotice('');
                }}
                onKeyDown={event => {
                  if (event.key === 'Enter' && !event.shiftKey) {
                    event.preventDefault();
                    sendMessage(input);
                  }
                }}
                placeholder="輸入訊息...（Shift+Enter 換行）"
                maxLength={900}
                rows={1}
              />
            </div>
            <button
              type="button"
              className={`chatbot-voice-button ${speechListening ? 'is-listening' : ''}`}
              onClick={toggleSpeechInput}
              disabled={loading || !speechSupported}
              aria-label={speechListening ? '停止語音輸入' : '語音輸入'}
              aria-pressed={speechListening}
              title={speechSupported ? '語音輸入' : '此瀏覽器暫不支援語音輸入'}
            >
              <svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
                <path d="M12 3a3 3 0 0 0-3 3v6a3 3 0 0 0 6 0V6a3 3 0 0 0-3-3z" />
                <path d="M19 10v2a7 7 0 0 1-14 0v-2" />
                <path d="M12 19v3" />
              </svg>
            </button>
            <button type="submit" className="chatbot-send-button" disabled={loading || !input.trim()} aria-label="送出">
              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
                <path d="M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z" />
              </svg>
            </button>
          </form>
          {speechNotice && <div className="chatbot-speech-note" aria-live="polite">{speechNotice}</div>}
          <div className="chatbot-hint">POWERED BY AI · 真人客服請洽 LINE @jafun</div>
        </section>
      )}
    </div>
  );
}

Object.assign(window, { ChatbotWidget });
