import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { motion } from 'framer-motion';
import { useCharacter } from '../../store/characterStore';
import { Avatar } from '../ui/Avatar';
import { Button } from '../ui/Button';
import { apiService } from '../../services/api';
import { NpcCharacter, NpcChatMessage, ShopItem } from '../../types';

const characterInfo: Record<NpcCharacter, { name: string; emoji: string }> = {
  frodo: { name: 'Frodo', emoji: '🧝' },
  sam: { name: 'Sam', emoji: '👨‍🌾' },
  gandalf: { name: 'Gandalf', emoji: '🧙‍♂️' },
};

const renderInlineRichText = (text: string): React.ReactNode[] => {
  const parts: React.ReactNode[] = [];
  const matcher = /\*\*(.+?)\*\*/g;
  let lastIndex = 0;
  let match = matcher.exec(text);
  while (match) {
    if (match.index > lastIndex) {
      parts.push(text.slice(lastIndex, match.index));
    }
    parts.push(<strong key={`bold-${match.index}`}>{match[1]}</strong>);
    lastIndex = match.index + match[0].length;
    match = matcher.exec(text);
  }
  if (lastIndex < text.length) {
    parts.push(text.slice(lastIndex));
  }
  return parts;
};

const renderRichMessageContent = (message: NpcChatMessage): React.ReactNode => {
  if (message.format !== 'markdown') {
    return message.content;
  }

  const lines = message.content.split('\n');
  const blocks: React.ReactNode[] = [];
  let listItems: string[] = [];

  const flushList = () => {
    if (listItems.length === 0) return;
    const listKey = `list-${blocks.length}`;
    blocks.push(
      <ul key={listKey} className="list-disc pl-5 space-y-1">
        {listItems.map((item, index) => (
          <li key={`${listKey}-${index}`}>{renderInlineRichText(item)}</li>
        ))}
      </ul>
    );
    listItems = [];
  };

  lines.forEach((line, index) => {
    const trimmed = line.trim();
    if (!trimmed) {
      flushList();
      return;
    }
    if (trimmed.startsWith('- ')) {
      listItems.push(trimmed.slice(2).trim());
      if (index === lines.length - 1) {
        flushList();
      }
      return;
    }
    flushList();
    blocks.push(
      <p key={`p-${index}`} className="leading-relaxed">
        {renderInlineRichText(trimmed)}
      </p>
    );
  });

  flushList();
  return <div className="space-y-1">{blocks}</div>;
};

const filterBargainMessages = (messages: NpcChatMessage[]): NpcChatMessage[] => {
  const hasCatalogMessage = messages.some((message) => message.metadata?.kind === 'shop-catalog');
  if (!hasCatalogMessage) {
    return messages;
  }

  return messages.filter((message) => message.metadata?.kind !== 'opener');
};

export const MapCharacterPanel: React.FC<{ onClose?: () => void; onGoldChange?: (gold: number) => void }> = ({ onClose, onGoldChange }) => {
  const {
    activeCharacter,
    setActiveCharacter,
    isChatLoading,
    chatMessages,
    setChatMessages,
    setChatLoading,
  } = useCharacter();
  const [draft, setDraft] = useState('');
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  const [shopItems, setShopItems] = useState<ShopItem[]>([]);
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  const [negotiationStatus, setNegotiationStatus] = useState<string>('');

  const updateGold = useCallback((value: number) => {
    onGoldChange?.(value);
  }, [onGoldChange]);
  const [error, setError] = useState<string | null>(null);

  const currentCharacter = useMemo(() => characterInfo[activeCharacter], [activeCharacter]);

  useEffect(() => {
    let mounted = true;
    const bootstrapConversation = async () => {
      try {
        setError(null);
        setChatLoading(true);
        const session = await apiService.getNpcChatSession(activeCharacter);
        if (!mounted) return;

        let messages = filterBargainMessages(session.messages || []);

        setChatMessages(messages);
        if (session.balance?.gold !== undefined) {
          updateGold(session.balance.gold);
        }
        if (session.negotiation?.status) {
          setNegotiationStatus(session.negotiation.status);
        }

        const hasCatalogMessage = messages.some(
          (chatMessage) => chatMessage.metadata?.kind === 'shop-catalog'
        );
        if (!hasCatalogMessage) {
          const catalog = await apiService.sendNpcMessage(activeCharacter, 'shop');
          if (!mounted) return;
          setChatMessages(filterBargainMessages(catalog.messages || []));
          if (catalog.balance?.gold !== undefined) {
            updateGold(catalog.balance.gold);
          }
          if (catalog.negotiation?.status) {
            setNegotiationStatus(catalog.negotiation.status);
          }
          if (catalog.shop_items) {
            setShopItems(catalog.shop_items);
          }
        }
      } catch {
        if (!mounted) return;
        setError('The trader is gathering wares. Try again in a moment.');
      } finally {
        if (mounted) {
          setChatLoading(false);
        }
      }
    };
    bootstrapConversation();
    return () => {
      mounted = false;
    };
  }, [activeCharacter, setChatLoading, setChatMessages, updateGold]);

  useEffect(() => {
    let mounted = true;
    const loadTradeData = async () => {
      try {
        const [items, balance] = await Promise.all([
          apiService.getShopItems(activeCharacter),
          apiService.getGoldBalance(),
        ]);
        if (!mounted) return;
        setShopItems(items);
        updateGold(balance);
      } catch {
        if (!mounted) return;
        setShopItems([]);
      }
    };
    loadTradeData();
    return () => { mounted = false; };
  }, [activeCharacter, updateGold]);

  const sendChat = async (messageInput: string) => {
    const message = messageInput.trim();
    if (!message) return;
    try {
      setError(null);
      setChatLoading(true);
      const response = await apiService.sendNpcMessage(activeCharacter, message);
      setChatMessages(filterBargainMessages(response.messages || []));
      if (response.balance?.gold !== undefined) {
        updateGold(response.balance.gold);
      }
      if (response.negotiation?.status) {
        setNegotiationStatus(response.negotiation.status);
      }
      if (response.shop_items) {
        setShopItems(response.shop_items);
      } else {
        const refreshedItems = await apiService.getShopItems(activeCharacter);
        setShopItems(refreshedItems);
      }
    } catch (sendError) {
      setError('The character did not answer. Try sending again.');
    } finally {
      setChatLoading(false);
    }
  };

  const handleSend = async () => {
    const message = draft.trim();
    if (!message) return;
    setDraft('');
    await sendChat(message);
  };

  const quickCharacters: NpcCharacter[] = ['frodo', 'sam', 'gandalf'];

  // --- Auto-scroll chat to bottom when messages change ---
  const chatPanelRef = React.useRef<HTMLDivElement>(null);
  useEffect(() => {
    if (chatPanelRef.current) {
      chatPanelRef.current.scrollTop = chatPanelRef.current.scrollHeight;
    }
  }, [chatMessages, isChatLoading]);

  return (
    <motion.aside
      initial={{ opacity: 0, x: 16 }}
      animate={{ opacity: 1, x: 0 }}
      transition={{ duration: 0.25 }}
      className="bg-gradient-to-br from-parchment-light to-parchment border border-gold-dark/40 rounded-xl shadow-lg p-4 space-y-4 relative"
    >
      {onClose && (
        <button
          className="absolute top-2 right-2 text-xl text-gold-dark hover:text-red-700 focus:outline-none bg-white/70 rounded-full w-8 h-8 flex items-center justify-center shadow"
          onClick={onClose}
          title="Close"
          aria-label="Close"
        >
          ×
        </button>
      )}
      <div className="flex items-center gap-3">
        <Avatar emoji={currentCharacter.emoji} size="lg" />
        <div>
          <h3 className="font-epic text-xl text-forest-dark">{currentCharacter.name}</h3>
          <p className="text-xs text-text-secondary">Trader Bargain</p>
        </div>
      </div>
      <div className="flex flex-wrap gap-2">
        {quickCharacters.map((character) => (
          <Button
            key={character}
            variant={character === activeCharacter ? 'epic' : 'small'}
            className="text-xs"
            onClick={() => setActiveCharacter(character)}
          >
            {characterInfo[character].emoji} {characterInfo[character].name}
          </Button>
        ))}
      </div>
      <div
        className="h-80 overflow-y-auto bg-white/50 rounded-lg border border-gold-dark/20 p-3 space-y-3"
        data-tour="dialogue-panel"
        data-testid="dialogue-panel"
        ref={chatPanelRef}
      >
        {chatMessages.length === 0 && !isChatLoading && (
          <p className="text-sm text-text-secondary">Start a bargain with your companion.</p>
        )}
        {chatMessages.map((message, index) => {
          // Special handling for sold/goodbye message: highlight or style if needed
          const isSoldMessage =
            message.role === 'assistant' &&
            /congratulations|sold|all wares are sold out|goodbye/i.test(message.content);
          return (
            <div
              key={`${message.role}-${index}`}
              className={message.role === 'assistant' ? 'text-left' : 'text-right'}
              data-testid={isSoldMessage ? 'sold-message' : undefined}
            >
              <div
                className={
                  message.role === 'assistant'
                    ? `inline-block max-w-[92%] rounded-lg px-3 py-2 bg-parchment-dark/70 text-text-primary text-sm break-words${
                        isSoldMessage ? ' border-2 border-gold-dark font-bold bg-yellow-100/80' : ''
                      }`
                    : 'inline-block max-w-[92%] rounded-lg px-3 py-2 bg-forest text-parchment-light text-sm break-words'
                }
              >
                {renderRichMessageContent(message)}
              </div>
            </div>
          );
        })}
        {isChatLoading && (
          <p className="text-xs text-text-secondary italic">{currentCharacter.name} is thinking…</p>
        )}
      </div>
      <div className="space-y-2">
        <textarea
          value={draft}
          onChange={(event) => setDraft(event.target.value)}
          onKeyDown={(event) => {
            if (event.key === 'Enter' && !event.shiftKey) {
              event.preventDefault();
              handleSend();
            }
          }}
          rows={3}
          placeholder={`Reply to ${currentCharacter.name}...`}
          className="w-full rounded-lg border border-gold-dark/30 bg-white/70 px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-gold/50 resize-none"
        />
        <div className="flex gap-2">
          <Button variant="epic" className="flex-1" onClick={handleSend} disabled={isChatLoading}>
            Send
          </Button>
        </div>
      </div>
      {error && <p className="text-xs text-red-700">{error}</p>}
    </motion.aside>
  );
};

MapCharacterPanel.displayName = 'MapCharacterPanel';
