import React, { useState, useEffect, useRef, useCallback } from 'react';
import { useAuth } from '../../contexts/AuthContext';
// import { useGame } from '../../contexts/GameContext'; // Removed invalid import
import { CombatView } from './CombatView';
import { CombatInventoryModal } from './CombatInventoryModal';
import { CombatState, CombatMessage, FloatingText, AnimationState, CombatActionResponse } from './CombatTypes';
import { useTranslation } from 'react-i18next';

// Updated props interface to match Game.tsx
interface CombatProps {
    combatState: any; // Using any for now to be flexible with backend response
    combatLog: any[];
    profile: any;
    playerState: any;
    equipment: any;
    locationImage?: string;
    onCombatAction: (action: string) => Promise<any>;
    onPvPAction: (action: string, targetId: number) => Promise<any>;
    onExitCombat: () => void;
    onExitPvPCombat: () => Promise<void>;
    addCombatLogEntry: (entry: any) => void;
    updatePlayerState: (data: any) => void;
    updateCombatState: (data: any) => void;

    // Kept for compatibility if passed
    onClose?: () => void;
}

import { useNotification } from '../../contexts/NotificationContext';

export const Combat: React.FC<CombatProps> = ({
    combatState: initialCombatData,
    combatLog: _combatLog,
    profile,
    playerState,
    equipment: _equipment,
    locationImage,
    onCombatAction,
    onPvPAction,
    onExitCombat,
    onExitPvPCombat,
    addCombatLogEntry: _addCombatLogEntry,
    updatePlayerState,
    updateCombatState: _updateCombatState,
    onClose
}) => {
    const { currentCharacter: _currentCharacter, refreshCharacters } = useAuth();
    const { t, i18n } = useTranslation();
    const { addNotification } = useNotification();

    const isPvP = initialCombatData?.is_pvp || false;

    // Helper to resolve localized names safely
    const resolveName = useCallback((name: any) => {
        if (!name) return '';
        if (typeof name === 'string') return name;
        if (typeof name === 'object') {
            return name[i18n.language] || name['en'] || name['es'] || 'Unknown';
        }
        return 'Unknown';
    }, [i18n.language]);

    // Helper to determine initial combat message
    const getInitialLogMessage = (): CombatMessage[] => {
        const timestamp = new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' });

        if (isPvP) {
            const isAttacker = initialCombatData?.pvp_combat?.is_attacker;
            return [{
                type: 'text',
                origin: 'system',
                timestamp,
                data: { text: isAttacker ? t('combat.log.pvp_attack') : t('combat.log.pvp_defense') }
            }];
        }

        // PvE Logic
        // If it's round 1 and enemy turn, likely an ambush or high initiative enemy
        // We don't have explicit 'ambush' flag, but we can infer or just use generic start
        // User requested 'getting ambushed when travelling', usually implies enemy starts
        const isAmbush = initialCombatData?.combat?.turn === 'enemy' && initialCombatData?.combat?.round === 1;

        if (isAmbush) {
            return [{
                type: 'text',
                origin: 'system',
                timestamp,
                data: { text: t('combat.log.ambush') }
            }];
        }

        return [{
            type: 'combat_start',
            origin: 'system',
            timestamp,
            data: { message: t('combat.log.combat_start') } // Fallback if 'combat_start' type isn't fully handled text-wise in View
        }];
    };

    // Calculate if it's your turn for PVP
    const computeYourTurn = () => {
        if (!isPvP) return initialCombatData?.turn === 'player';
        const pvp = initialCombatData?.pvp_combat;
        if (!pvp) return false;
        // your_turn comes directly from API, or we calculate it
        if (pvp.your_turn !== undefined) return pvp.your_turn;
        const isAttacker = pvp.is_attacker;
        const currentTurn = pvp.current_turn || pvp.turn;
        return (isAttacker && currentTurn === 'attacker') || (!isAttacker && currentTurn === 'defender');
    };

    // --- State Management ---
    // We synchronize local state with props, but manage animations locally
    const [localCombatState, setLocalCombatState] = useState<CombatState>({
        inCombat: true,
        turn: initialCombatData?.turn || initialCombatData?.pvp_combat?.current_turn || 'player',
        yourTurn: computeYourTurn(),
        npcId: initialCombatData?.combat?.npc_id || initialCombatData?.pvp_combat?.defender?.id,
        npcName: resolveName(initialCombatData?.combat?.npc_name) ||
            (initialCombatData?.pvp_combat?.is_attacker ? initialCombatData?.pvp_combat?.defender?.username : initialCombatData?.pvp_combat?.attacker?.username),
        npcHp: initialCombatData?.combat?.npc_hp ||
            (initialCombatData?.pvp_combat?.is_attacker ? initialCombatData?.pvp_combat?.defender?.hp : initialCombatData?.pvp_combat?.attacker?.hp) || 100,
        npcMaxHp: initialCombatData?.combat?.npc_max_hp ||
            (initialCombatData?.pvp_combat?.is_attacker ? initialCombatData?.pvp_combat?.defender?.max_hp : initialCombatData?.pvp_combat?.attacker?.max_hp) || 100,
        npcImage: initialCombatData?.combat?.npc_image ||
            (initialCombatData?.pvp_combat?.is_attacker ? initialCombatData?.pvp_combat?.defender?.image : initialCombatData?.pvp_combat?.attacker?.image),
        playerHp: playerState?.health || profile?.hp || 100,
        playerMaxHp: playerState?.max_health || profile?.max_hp || 100,
        messages: getInitialLogMessage(),
        round: initialCombatData?.combat?.round || 1,
        isPvP: isPvP,
        opponentName: isPvP
            ? (initialCombatData?.pvp_combat?.is_attacker ? initialCombatData?.pvp_combat?.defender?.username : initialCombatData?.pvp_combat?.attacker?.username)
            : undefined,
        turnTimeRemaining: initialCombatData?.pvp_combat?.time_remaining ?? initialCombatData?.turn_time_remaining
    });

    const [animState, setAnimState] = useState<AnimationState>({
        shaking: false, // Deprecated, but kept for safe removal if needed
        flashing: false, // Deprecated
        enemyAttacking: false,
        playerAttacking: false,
        playerHit: false,
        npcHit: false
    });

    const [floatingTexts, setFloatingTexts] = useState<FloatingText[]>([]);
    // const [isThinking, setIsThinking] = useState(false); // Unused for now
    const [messageQueue, setMessageQueue] = useState<CombatMessage[]>([]);
    const [isProcessingQueue, setIsProcessingQueue] = useState(false);
    const [combatResult, setCombatResult] = useState<'victory' | 'defeat' | 'fled' | null>(null);
    const [showSuppliesModal, setShowSuppliesModal] = useState(false);

    // --- Refs ---
    const processingRef = useRef(false);
    const queueRef = useRef<CombatMessage[]>([]);
    // Store server player HP to apply when damage floating text appears
    const pendingPlayerHpRef = useRef<{ hp: number; max_hp: number } | null>(null);
    // Store server player XP to apply when XP floating text appears
    const pendingPlayerXpRef = useRef<{ xp: number; level: number } | null>(null);

    // Update queueRef
    useEffect(() => {
        queueRef.current = messageQueue;
    }, [messageQueue]);

    // Update local state when props change (especially for PvP live updates)
    // This handles both initial state and WebSocket updates (for the passive player)
    useEffect(() => {
        if (initialCombatData) {
            // Get time remaining from multiple possible paths
            const newTimeRemaining =
                initialCombatData?.pvp_combat?.time_remaining ??
                initialCombatData?.turn_time_remaining ??
                undefined;

            // Calculate yourTurn for PVP
            let newYourTurn: boolean | undefined;
            if (isPvP) {
                const pvp = initialCombatData?.pvp_combat;
                if (pvp?.your_turn !== undefined) {
                    newYourTurn = pvp.your_turn;
                } else if (pvp) {
                    const isAttacker = pvp.is_attacker;
                    const currentTurn = pvp.current_turn || pvp.turn;
                    newYourTurn = (isAttacker && currentTurn === 'attacker') || (!isAttacker && currentTurn === 'defender');
                }
            } else {
                newYourTurn = initialCombatData.turn === 'player' || initialCombatData.combat?.turn === 'player';
            }

            // For PVP: sync HP from WebSocket update for passive player
            let newPlayerHp: number | undefined;
            let newNpcHp: number | undefined;
            if (isPvP && initialCombatData?.pvp_combat) {
                const pvp = initialCombatData.pvp_combat;
                const isAttacker = pvp.is_attacker;

                // My HP vs opponent HP based on role
                if (isAttacker) {
                    newPlayerHp = pvp.attacker?.hp;
                    newNpcHp = pvp.defender?.hp;
                } else {
                    newPlayerHp = pvp.defender?.hp;
                    newNpcHp = pvp.attacker?.hp;
                }
            }

            // Handle incoming messages from WebSocket (for passive player)
            if (isPvP && initialCombatData?.messages && Array.isArray(initialCombatData.messages)) {
                const timestamp = new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' });

                for (const msg of initialCombatData.messages) {
                    // Skip messages originating from 'player' (active user) as they are handled by the immediate API response
                    if (msg.origin === 'player') continue;

                    // Add message to combat log (only for non-player origin)
                    setLocalCombatState(prev => ({
                        ...prev,
                        messages: [...prev.messages, { ...msg, timestamp }]
                    }));

                    // Trigger animations via WebSocket message (passive player)
                    if ((msg.type === 'damage' || msg.type === 'player_attack') && msg.origin === 'enemy') {
                        // Enemy dealt damage to me
                        triggerAnim('enemyAttacking', 400);
                        setTimeout(() => {
                            addFloatingText(`-${msg.data?.damage || 0}`, 'damage', 'player');
                            triggerAnim('playerHit', 300);
                        }, 200);
                    } else if (msg.type === 'miss' && msg.origin === 'enemy') {
                        // Enemy missed me
                        triggerAnim('enemyAttacking', 400);
                        setTimeout(() => {
                            addFloatingText('Miss!', 'miss', 'player');
                        }, 200);
                    } else if (msg.type === 'flee_success') {
                        // Opponent fled -> I win (msg origin is 'enemy' after swap? NO wait.)
                        // Backend: attacker_fled=True.
                        // Message generated: "player fled". Origin="player".
                        // Backend swaps origin to "enemy" for me.
                        // So I receive: msg.type='flee_success', origin='enemy'.
                        setCombatResult('victory');
                    } else if (msg.type === 'victory' || msg.type === 'player_defeated') {
                        // If I receive 'victory', and origin='player' (skipped).
                        // If origin='enemy' -> Enemy Won -> I Defeat.
                        if (msg.origin === 'player') {
                            setCombatResult('victory');
                        } else {
                            setCombatResult('defeat');
                        }
                    }
                }
            }

            // Handle combat_over from WebSocket or initial state (including fled states which might not set combat_over flag explicitly in all paths)
            const pvp = initialCombatData?.pvp_combat;
            const myId = pvp?.is_attacker
                ? pvp?.attacker?.id
                : pvp?.defender?.id;

            // Check if someone fled (Robust check for both combat_over=true AND implicit state)
            const iAmAttacker = pvp?.is_attacker;
            const opponentFled = iAmAttacker ? pvp?.defender_fled : pvp?.attacker_fled;
            const iFled = iAmAttacker ? pvp?.attacker_fled : pvp?.defender_fled;

            if (initialCombatData?.combat_over || opponentFled || iFled) {
                if (opponentFled) {
                    // Opponent fled - I "win" by default
                    setCombatResult('victory');
                } else if (iFled) {
                    // I fled successfully
                    setCombatResult('fled');
                } else if (initialCombatData?.winner_id === myId) {
                    setCombatResult('victory');
                } else if (initialCombatData?.winner_id) {
                    setCombatResult('defeat');
                }
            }

            setLocalCombatState(prev => ({
                ...prev,
                turn: initialCombatData.turn || initialCombatData.combat?.turn || initialCombatData.pvp_combat?.current_turn || prev.turn,
                yourTurn: newYourTurn !== undefined ? newYourTurn : prev.yourTurn,
                round: initialCombatData?.combat?.round ?? prev.round,
                turnTimeRemaining: newTimeRemaining !== undefined ? newTimeRemaining : prev.turnTimeRemaining,
                // Sync HP for PVP from WebSocket updates
                ...(isPvP && newPlayerHp !== undefined ? { playerHp: newPlayerHp } : {}),
                ...(isPvP && newNpcHp !== undefined ? { npcHp: newNpcHp } : {})
            }));
        }
    }, [initialCombatData, isPvP]);


    // --- Handlers ---
    // Move ref to component scope
    const cleanupIntervalRef = useRef<NodeJS.Timeout | null>(null);

    const addFloatingText = (text: string, type: FloatingText['type'], origin: 'player' | 'enemy') => {
        const id = Math.random().toString(36).substr(2, 9);
        // Fixed position at center - no random offset for turn-based combat
        const x = 50;
        const y = 50;

        setFloatingTexts(prev => [...prev, { id, text, type, x, y, origin, timestamp: Date.now() }]);
    };

    // Clean up floats
    useEffect(() => {
        cleanupIntervalRef.current = setInterval(() => {
            // Only clean up if we are NOT in a result state (victory/defeat) to prevent race conditions
            setFloatingTexts(prev => {
                if (prev.length === 0) return prev;
                return prev.filter(ft => Date.now() - ft.timestamp < 5000);
            });
        }, 500);
        return () => {
            if (cleanupIntervalRef.current) clearInterval(cleanupIntervalRef.current);
        };
    }, []);

    // Timer countdown effect for PVP
    useEffect(() => {
        if (!isPvP || combatResult) return; // Only for active PVP combat

        const timerInterval = setInterval(() => {
            setLocalCombatState(prev => {
                if (prev.turnTimeRemaining !== undefined && prev.turnTimeRemaining > 0) {
                    const newTime = prev.turnTimeRemaining - 1;

                    // If timer just hit 0 and it was your turn, switch turn and log it
                    if (newTime === 0 && prev.yourTurn) {
                        // Add timeout message to log
                        const timestamp = new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' });
                        return {
                            ...prev,
                            turnTimeRemaining: newTime,
                            yourTurn: false, // Pass turn to opponent
                            messages: [...prev.messages, {
                                type: 'text',
                                origin: 'system' as const,
                                data: { text: t('combat.turn_timeout') },
                                timestamp
                            }]
                        };
                    }

                    return { ...prev, turnTimeRemaining: newTime };
                }
                return prev;
            });
        }, 1000);

        return () => clearInterval(timerInterval);
    }, [isPvP, combatResult, t]);

    const triggerAnim = (anim: keyof AnimationState, duration: number = 500) => {
        setAnimState(prev => ({ ...prev, [anim]: true }));
        setTimeout(() => {
            setAnimState(prev => ({ ...prev, [anim]: false }));
        }, duration);
    };

    // --- Message Processing ---

    const processMessage = useCallback((msg: CombatMessage) => {
        const { type, origin, data } = msg;

        // Force NPC HP to 0 on victory to ensure bar is empty, as backend might report pre-death HP
        if (type === 'victory') {
            setLocalCombatState(prev => ({
                ...prev,
                npcHp: 0
            }));
        }

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

        setLocalCombatState(prev => ({
            ...prev,
            messages: [...prev.messages, msgWithTimestamp]
        }));

        switch (type) {
            case 'combat_start':
                break;

            case 'player_attack':
                triggerAnim('playerAttacking');
                triggerAnim('npcHit', 300); // Enemy takes damage
                if (data.damage) {
                    addFloatingText(`-${data.damage}`, 'damage', 'enemy');
                    // HP is updated via server value in handlePvEAction
                }
                break;

            case 'player_miss':
                addFloatingText(t('combat.miss'), 'miss', 'enemy');
                break;

            case 'enemy_attack':
            case 'monster_attack':
            case 'flee_fail':  // Failed flee results in enemy counter-attack
                triggerAnim('enemyAttacking');
                triggerAnim('playerHit', 300); // Player takes damage
                if (data.damage) {
                    addFloatingText(`-${data.damage}`, 'damage', 'player');
                    // Apply server player HP when floating text appears
                    if (pendingPlayerHpRef.current) {
                        const { hp, max_hp } = pendingPlayerHpRef.current;
                        setLocalCombatState(prev => ({
                            ...prev,
                            playerHp: hp,
                            playerMaxHp: max_hp
                        }));
                        updatePlayerState({ hp, max_hp });
                        pendingPlayerHpRef.current = null;
                    }
                }
                break;

            case 'enemy_miss':
                addFloatingText(t('combat.miss'), 'miss', 'player');
                break;

            case 'enemy_defend':
                addFloatingText(`+${data.heal}`, 'heal', 'enemy');
                break;

            case 'enemy_special':
                triggerAnim('enemyAttacking');
                triggerAnim('flashing', 500);
                triggerAnim('shaking', 500);
                if (data.damage) {
                    addFloatingText(`-${data.damage}!`, 'crit', 'player');
                }
                break;

            case 'effect_damage':
                addFloatingText(`-${data.damage}`, 'damage', origin === 'enemy' ? 'enemy' : 'player');
                break;

            case 'effect_bleeding':
                addFloatingText(`-${data.damage}`, 'damage', origin === 'player' ? 'enemy' : 'player');
                break;

            case 'xp_gain':
                addFloatingText(`+${data.amount} XP`, 'info', 'player');
                // Sync XP bar with floating text using server value
                if (pendingPlayerXpRef.current) {
                    updatePlayerState({ xp: pendingPlayerXpRef.current.xp, level: pendingPlayerXpRef.current.level });
                    pendingPlayerXpRef.current = null;
                } else if (data.xp !== undefined) {
                    // Fallback to message data if ref is missing (shouldn't happen usually)
                    updatePlayerState({ xp: data.xp, level: data.level });
                }
                break;

            case 'victory':
                // Stop cleanup interval to freeze the DOM state regarding floating texts
                if (cleanupIntervalRef.current) clearInterval(cleanupIntervalRef.current);

                // Delay victory state to allow final animations (floating text) to persist
                setTimeout(() => {
                    setCombatResult('victory');
                }, 1000);
                break;

            case 'player_defeated':
                if (cleanupIntervalRef.current) clearInterval(cleanupIntervalRef.current);
                setTimeout(() => {
                    setCombatResult('defeat');
                }, 2000);
                break;

            case 'item_used':
                if (data.hp_restore) {
                    setTimeout(() => addFloatingText(`+${data.hp_restore}`, 'heal', 'player'), 200);
                }
                if (data.stamina_restore) {
                    setTimeout(() => addFloatingText(`+${data.stamina_restore}`, 'stamina', 'player'), 400);
                }
                break;

            case 'effect_applied':
                addFloatingText(`${data.effect_icon || ''} ${data.effect_name}`, 'info', data.target === 'enemy' ? 'enemy' : 'player');
                break;

            case 'flee_success':
                if (cleanupIntervalRef.current) clearInterval(cleanupIntervalRef.current);
                setTimeout(() => {
                    setCombatResult('fled');
                }, 500);
                break;

            case 'quest_update':
                addNotification(data.message || 'Quest Progress', 'quest');
                break;

            // ── Skill messages ──
            case 'skill_attack':
                triggerAnim('playerAttacking');
                triggerAnim('npcHit', 300);
                if (data.damage) {
                    const label = data.hits > 1
                        ? `${data.skill_icon || '⚔️'} -${data.damage} (x${data.hits})`
                        : `${data.skill_icon || '⚔️'} -${data.damage}`;
                    addFloatingText(label, 'damage', 'enemy');
                }
                break;

            case 'skill_heal':
                if (data.heal) {
                    addFloatingText(`${data.skill_icon || '💚'} +${data.heal}`, 'heal', 'player');
                    if (pendingPlayerHpRef.current) {
                        const { hp, max_hp } = pendingPlayerHpRef.current;
                        setLocalCombatState(prev => ({
                            ...prev, playerHp: hp, playerMaxHp: max_hp
                        }));
                        updatePlayerState({ hp, max_hp });
                        pendingPlayerHpRef.current = null;
                    }
                }
                break;

            case 'skill_buff':
                addFloatingText(`${data.skill_icon || '🛡️'} ${data.skill_name ? (typeof data.skill_name === 'object' ? (data.skill_name[(i18n as any).language] || data.skill_name.en) : data.skill_name) : 'Buff'}`, 'info', 'player');
                break;

            case 'skill_effect':
                if (data.message) {
                    addFloatingText(data.message, 'info', 'enemy');
                }
                break;

            case 'skill_analyze':
                addFloatingText(`${data.skill_icon || '🔍'} Analyzed!`, 'info', 'enemy');
                break;
        }
    }, [t]);

    const processQueue = useCallback(async () => {
        if (processingRef.current || queueRef.current.length === 0) return;

        processingRef.current = true;
        setIsProcessingQueue(true);

        const msg = queueRef.current[0];

        processMessage(msg);

        // Determine delay based on message type
        let delay = 600;
        if (msg.type === 'enemy_attack' || msg.type === 'enemy_special') delay = 1200;
        // Increase victory delay in queue processing so the UI doesn't rush
        if (msg.type === 'victory') delay = 2000;
        if (msg.origin === 'enemy' && msg.type !== 'flee_fail') delay = 1000;

        await new Promise(resolve => setTimeout(resolve, delay));

        setMessageQueue(prev => prev.slice(1));
        processingRef.current = false;

    }, [processMessage]);

    useEffect(() => {
        if (messageQueue.length > 0 && !processingRef.current) {
            processQueue();
        } else if (messageQueue.length === 0 && isProcessingQueue) {
            // Queue just finished processing
            setIsProcessingQueue(false);
        }
    }, [messageQueue, processQueue, isProcessingQueue]);


    const handlePvEAction = async (action: string) => {
        if (isProcessingQueue) return;

        try {
            if (localCombatState.turn !== 'player') return;

            // Use the prop function instead of direct fetch
            const data: CombatActionResponse = await onCombatAction(action);

            if (data && data.success && data.messages) {
                setMessageQueue(data.messages);

                // Apply server HP values IMMEDIATELY
                if (data.combat) {
                    setLocalCombatState(prev => ({
                        ...prev,
                        npcHp: data.combat.npc_hp,
                        npcMaxHp: data.combat.npc_max_hp,
                        turn: data.combat.turn,
                        round: data.combat.round,
                        npcName: resolveName(data.combat.npc_name) || prev.npcName
                    }));
                } else if (data.combat_over && data.player_won) {
                    // Combat ended with victory but data.combat is null - set enemy HP to 0
                    setLocalCombatState(prev => ({
                        ...prev,
                        npcHp: 0
                    }));
                }

                if (data.player) {
                    // Store player HP to apply when enemy_attack message is processed
                    pendingPlayerHpRef.current = { hp: data.player.hp, max_hp: data.player.max_hp };
                    // Store player XP to apply when xp_gain message is processed
                    pendingPlayerXpRef.current = { xp: data.player.xp, level: data.player.level };
                    refreshCharacters();
                }
            }
        } catch (err) {
            console.error(err);
        }
    };

    const handlePvPActionWrapper = async (action: string) => {
        if (isProcessingQueue) return;
        try {
            // Call PVP action and process response for animations
            const response = await onPvPAction(action, 0);

            if (response) {
                // Determine if this is an attack action
                const isAttack = action === 'attack';

                // Trigger player attack animation for attacks
                if (isAttack) {
                    triggerAnim('playerAttacking', 400);
                }

                // Process messages for animations and add to combat log
                if (response.messages && Array.isArray(response.messages)) {
                    const timestamp = new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' });

                    for (const msg of response.messages) {
                        // Add message to combat log
                        setLocalCombatState(prev => ({
                            ...prev,
                            messages: [...prev.messages, { ...msg, timestamp }]
                        }));

                        // Trigger animations based on message type
                        if ((msg.type === 'damage' || msg.type === 'player_attack') && msg.origin === 'player') {
                            // Player dealt damage - show damage on enemy
                            setTimeout(() => {
                                addFloatingText(`-${msg.data?.damage || 0}`, 'damage', 'enemy');
                                triggerAnim('npcHit', 300);
                            }, 200);
                        } else if (msg.type === 'miss' && msg.origin === 'player') {
                            setTimeout(() => {
                                addFloatingText('Miss!', 'miss', 'enemy');
                            }, 200);
                        } else if (msg.type === 'flee_success') {
                            // Successfully fled - trigger combat result
                            setCombatResult('fled');
                        } else if (msg.type === 'flee_fail') {
                            // Failed to flee - just the log message was added
                        } else if (msg.type === 'victory') {
                            setCombatResult('victory');
                        } else if (msg.type === 'player_defeated') {
                            setCombatResult('defeat');
                        }
                    }
                }

                // Update HP from response if available
                const isAttacker = initialCombatData?.pvp_combat?.is_attacker;
                if (response.attacker_hp !== undefined && response.defender_hp !== undefined) {
                    const myHp = isAttacker ? response.attacker_hp : response.defender_hp;
                    const opponentHp = isAttacker ? response.defender_hp : response.attacker_hp;

                    setLocalCombatState(prev => ({
                        ...prev,
                        npcHp: opponentHp,
                        playerHp: myHp
                    }));
                }

                // Handle combat over state
                if (response.combat_over) {
                    if (response.winner_id === initialCombatData?.pvp_combat?.id) {
                        // Not used - winner_id is player id, not combat id
                    }
                    // Combat result will be set by message type above
                }

                // Update turn state
                setLocalCombatState(prev => ({
                    ...prev,
                    yourTurn: false // After action, it's always the other player's turn
                }));
            }
        } catch (err) {
            console.error('PvP action error:', err);
        }
    };

    const [isClosing, setIsClosing] = useState(false);

    const handleCloseWrapper = () => {
        if (isClosing) return;
        setIsClosing(true);

        // Clear all dynamic elements to allow React to reconcile locally before unmounting
        setFloatingTexts([]);
        setAnimState({ shaking: false, flashing: false, enemyAttacking: false, playerAttacking: false });
        setMessageQueue([]);

        // Small delay to ensure the DOM is clear of floating texts before unmounting the component
        setTimeout(() => {
            if (isPvP) {
                onExitPvPCombat();
            } else {
                onExitCombat();
            }
            if (onClose) onClose();
        }, 50);
    };

    const handleUseItem = async (itemId: string) => {
        // Close modal and use item in combat
        setShowSuppliesModal(false);
        if (isPvP) {
            await handlePvPActionWrapper('use_item');
        } else {
            await handlePvEActionWithItem('use_item', itemId);
        }
    };

    const handlePvEActionWithItem = async (action: string, itemId?: string) => {
        if (isProcessingQueue) return;

        try {
            if (localCombatState.turn !== 'player') return;

            // Build action payload 
            const actionPayload = itemId ? `${action}:${itemId}` : action;
            const data: CombatActionResponse = await onCombatAction(actionPayload);

            if (data && data.success && data.messages) {
                setMessageQueue(data.messages);

                if (data.combat) {
                    setLocalCombatState(prev => ({
                        ...prev,
                        npcHp: data.combat.npc_hp,
                        npcMaxHp: data.combat.npc_max_hp,
                        turn: data.combat.turn,
                        round: data.combat.round,
                        npcName: resolveName(data.combat.npc_name) || prev.npcName
                    }));
                } else if (data.combat_over && data.player_won) {
                    setLocalCombatState(prev => ({
                        ...prev,
                        npcHp: 0
                    }));
                }

                if (data.player) {
                    pendingPlayerHpRef.current = { hp: data.player.hp, max_hp: data.player.max_hp };
                    pendingPlayerXpRef.current = { xp: data.player.xp, level: data.player.level };
                    refreshCharacters();
                }
            }
        } catch (err) {
            console.error(err);
        }
    };


    return (
        <>
            <CombatView
                state={localCombatState}
                animState={animState}
                floatingTexts={floatingTexts}
                onAction={isPvP ? handlePvPActionWrapper : handlePvEAction}
                onClose={handleCloseWrapper}
                onShowSupplies={() => setShowSuppliesModal(true)}
                isProcessing={isProcessingQueue}
                playerStamina={playerState?.stamina || 0}
                combatResult={combatResult}
                equipment={_equipment}
                playerName={profile?.name}
                locationImage={locationImage}
            />
            {/* Supplies modal */}
            <CombatInventoryModal
                isOpen={showSuppliesModal}
                onClose={() => setShowSuppliesModal(false)}
                onUseItem={handleUseItem}
                inventory={playerState?.inventory || []}
            />
        </>
    );
};
