"""
Integration tests for Combat API endpoints.

Tests the REST API endpoints for combat functionality.
"""

import pytest
from unittest.mock import Mock, patch, MagicMock
from flask import Flask
import json

from app import create_app
from app.api.combat import combat_bp
from app.models.combat import CombatEncounter, Combatant, CombatStatus
from app.models.stats import Stats
from app.models.enemy import EnemyTemplate, EnemyDifficulty
from app.services.combat_service import CombatService, ActionResult, CombatRewards


# =============================================================================
# Test Fixtures
# =============================================================================

@pytest.fixture
def app():
    """Create test Flask application."""
    app = create_app('development')
    app.config['TESTING'] = True
    return app


@pytest.fixture
def client(app):
    """Create test client."""
    return app.test_client()


@pytest.fixture
def sample_stats():
    """Sample stats for testing."""
    return Stats(
        strength=12,
        dexterity=14,
        constitution=10,
        intelligence=10,
        wisdom=10,
        charisma=10,
        luck=10
    )


@pytest.fixture
def sample_combatant(sample_stats):
    """Sample player combatant."""
    return Combatant(
        combatant_id="test_char_001",
        name="Test Hero",
        is_player=True,
        current_hp=50,
        max_hp=50,
        current_mp=30,
        max_mp=30,
        stats=sample_stats,
        abilities=["basic_attack", "power_strike"],
    )


@pytest.fixture
def sample_enemy_combatant(sample_stats):
    """Sample enemy combatant."""
    return Combatant(
        combatant_id="test_goblin_0",
        name="Test Goblin",
        is_player=False,
        current_hp=25,
        max_hp=25,
        current_mp=10,
        max_mp=10,
        stats=sample_stats,
        abilities=["basic_attack"],
    )


@pytest.fixture
def sample_encounter(sample_combatant, sample_enemy_combatant):
    """Sample combat encounter."""
    encounter = CombatEncounter(
        encounter_id="test_encounter_001",
        combatants=[sample_combatant, sample_enemy_combatant],
        turn_order=[sample_combatant.combatant_id, sample_enemy_combatant.combatant_id],
        round_number=1,
        current_turn_index=0,
        status=CombatStatus.ACTIVE,
    )
    return encounter


# =============================================================================
# List Enemies Endpoint Tests
# =============================================================================

class TestListEnemiesEndpoint:
    """Tests for GET /api/v1/combat/enemies endpoint."""

    def test_list_enemies_success(self, client):
        """Test listing all enemy templates."""
        response = client.get('/api/v1/combat/enemies')

        assert response.status_code == 200
        data = response.get_json()

        assert data['status'] == 200
        assert 'result' in data
        assert 'enemies' in data['result']

        enemies = data['result']['enemies']
        assert isinstance(enemies, list)
        assert len(enemies) >= 6  # We have 6 sample enemies

        # Verify enemy structure
        enemy_ids = [e['enemy_id'] for e in enemies]
        assert 'goblin' in enemy_ids

    def test_list_enemies_filter_by_difficulty(self, client):
        """Test filtering enemies by difficulty."""
        response = client.get('/api/v1/combat/enemies?difficulty=easy')

        assert response.status_code == 200
        data = response.get_json()

        enemies = data['result']['enemies']
        for enemy in enemies:
            assert enemy['difficulty'] == 'easy'

    def test_list_enemies_filter_by_tag(self, client):
        """Test filtering enemies by tag."""
        response = client.get('/api/v1/combat/enemies?tag=humanoid')

        assert response.status_code == 200
        data = response.get_json()

        enemies = data['result']['enemies']
        for enemy in enemies:
            assert 'humanoid' in [t.lower() for t in enemy['tags']]


# =============================================================================
# Get Enemy Details Endpoint Tests
# =============================================================================

class TestGetEnemyEndpoint:
    """Tests for GET /api/v1/combat/enemies/<enemy_id> endpoint."""

    def test_get_enemy_success(self, client):
        """Test getting enemy details."""
        response = client.get('/api/v1/combat/enemies/goblin')

        assert response.status_code == 200
        data = response.get_json()

        assert data['status'] == 200
        # Enemy data is returned directly in result (not nested under 'enemy' key)
        assert data['result']['enemy_id'] == 'goblin'
        assert 'base_stats' in data['result']
        assert 'loot_table' in data['result']

    def test_get_enemy_not_found(self, client):
        """Test getting non-existent enemy."""
        response = client.get('/api/v1/combat/enemies/nonexistent_12345')

        assert response.status_code == 404
        data = response.get_json()
        assert data['status'] == 404


# =============================================================================
# Start Combat Endpoint Tests
# =============================================================================

class TestStartCombatEndpoint:
    """Tests for POST /api/v1/combat/start endpoint."""

    def test_start_combat_requires_auth(self, client):
        """Test that start combat endpoint requires authentication."""
        response = client.post(
            '/api/v1/combat/start',
            json={
                'session_id': 'test_session_001',
                'enemy_ids': ['goblin', 'goblin']
            }
        )

        # Should return 401 Unauthorized without valid session
        assert response.status_code == 401

    def test_start_combat_missing_session_id(self, client):
        """Test starting combat without session_id."""
        response = client.post(
            '/api/v1/combat/start',
            json={'enemy_ids': ['goblin']},
        )

        assert response.status_code in [400, 401]

    def test_start_combat_missing_enemies(self, client):
        """Test starting combat without enemies."""
        response = client.post(
            '/api/v1/combat/start',
            json={'session_id': 'test_session'},
        )

        assert response.status_code in [400, 401]


# =============================================================================
# Execute Action Endpoint Tests
# =============================================================================

class TestExecuteActionEndpoint:
    """Tests for POST /api/v1/combat/<session_id>/action endpoint."""

    def test_action_requires_auth(self, client):
        """Test that action endpoint requires authentication."""
        response = client.post(
            '/api/v1/combat/test_session/action',
            json={
                'action_type': 'attack',
                'target_ids': ['enemy_001']
            }
        )

        # Should return 401 Unauthorized without valid session
        assert response.status_code == 401

    def test_action_missing_type(self, client):
        """Test action with missing action_type still requires auth."""
        # Without auth, returns 401 regardless of payload issues
        response = client.post(
            '/api/v1/combat/test_session/action',
            json={'target_ids': ['enemy_001']}
        )

        assert response.status_code == 401


# =============================================================================
# Enemy Turn Endpoint Tests
# =============================================================================

class TestEnemyTurnEndpoint:
    """Tests for POST /api/v1/combat/<session_id>/enemy-turn endpoint."""

    def test_enemy_turn_requires_auth(self, client):
        """Test that enemy turn endpoint requires authentication."""
        response = client.post('/api/v1/combat/test_session/enemy-turn')

        assert response.status_code == 401


# =============================================================================
# Flee Endpoint Tests
# =============================================================================

class TestFleeEndpoint:
    """Tests for POST /api/v1/combat/<session_id>/flee endpoint."""

    def test_flee_requires_auth(self, client):
        """Test that flee endpoint requires authentication."""
        response = client.post('/api/v1/combat/test_session/flee')

        assert response.status_code == 401


# =============================================================================
# Get Combat State Endpoint Tests
# =============================================================================

class TestGetCombatStateEndpoint:
    """Tests for GET /api/v1/combat/<session_id>/state endpoint."""

    def test_state_requires_auth(self, client):
        """Test that state endpoint requires authentication."""
        response = client.get('/api/v1/combat/test_session/state')

        assert response.status_code == 401


# =============================================================================
# End Combat Endpoint Tests
# =============================================================================

class TestEndCombatEndpoint:
    """Tests for POST /api/v1/combat/<session_id>/end endpoint."""

    def test_end_requires_auth(self, client):
        """Test that end combat endpoint requires authentication."""
        response = client.post('/api/v1/combat/test_session/end')

        assert response.status_code == 401


# =============================================================================
# Response Format Tests
# =============================================================================

class TestCombatAPIResponseFormat:
    """Tests for API response format consistency."""

    def test_enemies_response_format(self, client):
        """Test that enemies list has standard response format."""
        response = client.get('/api/v1/combat/enemies')
        data = response.get_json()

        # Standard response fields
        assert 'app' in data
        assert 'version' in data
        assert 'status' in data
        assert 'timestamp' in data
        assert 'result' in data

        # Should not have error for successful request
        assert data['error'] is None or 'error' not in data or data['error'] == {}

    def test_enemy_details_response_format(self, client):
        """Test that enemy details has standard response format."""
        response = client.get('/api/v1/combat/enemies/goblin')
        data = response.get_json()

        assert data['status'] == 200
        assert 'result' in data

        # Enemy data is returned directly in result
        enemy = data['result']
        # Required enemy fields
        assert 'enemy_id' in enemy
        assert 'name' in enemy
        assert 'description' in enemy
        assert 'base_stats' in enemy
        assert 'difficulty' in enemy

    def test_not_found_response_format(self, client):
        """Test 404 response format."""
        response = client.get('/api/v1/combat/enemies/nonexistent_enemy_xyz')
        data = response.get_json()

        assert data['status'] == 404
        assert 'error' in data
        assert data['error'] is not None


# =============================================================================
# Content Type Tests
# =============================================================================

class TestCombatAPIContentType:
    """Tests for content type handling."""

    def test_json_content_type_response(self, client):
        """Test that API returns JSON content type."""
        response = client.get('/api/v1/combat/enemies')

        assert response.content_type == 'application/json'

    def test_accepts_json_payload(self, client):
        """Test that API accepts JSON payloads."""
        response = client.post(
            '/api/v1/combat/start',
            data=json.dumps({
                'session_id': 'test',
                'enemy_ids': ['goblin']
            }),
            content_type='application/json'
        )

        # Should process JSON (even if auth fails)
        assert response.status_code in [200, 400, 401]
